PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "portability/instr_time.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "pgbench.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

struct  Variable
 
struct  SimpleStats
 
struct  StatsData
 
struct  CState
 
struct  TState
 
struct  Command
 
struct  ParsedScript
 
struct  BuiltinScript
 

Macros

#define M_PI   3.14159265358979323846
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define pthread_t   void *
 
#define MAXCLIENTS   1024
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define INVALID_THREAD   ((pthread_t) 0)
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   10
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define MAX_PREPARE_NAME   32
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct SimpleStats SimpleStats
 
typedef struct StatsData StatsData
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT, CSTATE_START_THROTTLE, CSTATE_THROTTLE, CSTATE_START_TX,
  CSTATE_START_COMMAND, CSTATE_WAIT_RESULT, CSTATE_SLEEP, CSTATE_END_COMMAND,
  CSTATE_END_TX, CSTATE_ABORTED, CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE, META_SET, META_SETSHELL, META_SHELL,
  META_SLEEP
}
 
enum  QueryMode { QUERY_SIMPLE, QUERY_EXTENDED, QUERY_PREPARED, NUM_QUERYMODE }
 

Functions

static void setIntValue (PgBenchValue *pv, int64 ival)
 
static void setDoubleValue (PgBenchValue *pv, double dval)
 
static bool evaluateExpr (TState *, CState *, PgBenchExpr *, PgBenchValue *)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
 
static void pgbench_error (const char *fmt,...) pg_attribute_printf(1
 
static void static void addScript (ParsedScript script)
 
static void * threadRun (void *arg)
 
static void setalarm (int seconds)
 
static void usage (void)
 
static bool is_an_int (const char *str)
 
int64 strtoint64 (const char *str)
 
static int64 getrand (TState *thread, int64 min, int64 max)
 
static int64 getExponentialRand (TState *thread, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (TState *thread, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (TState *thread, int64 center)
 
static void initSimpleStats (SimpleStats *ss)
 
static void addToSimpleStats (SimpleStats *ss, double val)
 
static void mergeSimpleStats (SimpleStats *acc, SimpleStats *ss)
 
static void initStats (StatsData *sd, time_t start_time)
 
static void accumStats (StatsData *stats, bool skipped, double lat, double lag)
 
static void executeStatement (PGconn *con, const char *sql)
 
static void tryExecuteStatement (PGconn *con, const char *sql)
 
static PGconndoConnect (void)
 
static void discard_response (CState *state)
 
static int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (CState *st, char *name)
 
static char * getVariable (CState *st, char *name)
 
static bool makeVariableNumeric (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static VariablelookupCreateVariable (CState *st, const char *context, char *name)
 
static bool putVariable (CState *st, const char *context, char *name, const char *value)
 
static bool putVariableNumber (CState *st, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (CState *st, const char *context, char *name, int64 value)
 
static char * parseVariable (const char *sql, int *eaten)
 
static char * replaceVariable (char **sql, char *param, int len, char *value)
 
static char * assignVariables (CState *st, char *sql)
 
static void getQueryParams (CState *st, const Command *command, const char **params)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool evalFunc (TState *thread, CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static MetaCommand getMetaCommand (const char *cmd)
 
static bool runShellCommand (CState *st, char *variable, char **argv, int argc)
 
static void preparedStatementName (char *buffer, int file, int state)
 
static void commandFailed (CState *st, const char *message)
 
static int chooseScript (TState *thread)
 
static bool sendCommand (CState *st, Command *command)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void doCustom (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initGenerateData (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static Commandprocess_sql_command (PQExpBuffer buf, const char *source)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printResults (TState *threads, StatsData *total, instr_time total_time, instr_time conn_total_time, int latency_late)
 
int main (int argc, char **argv)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 

Variables

int nxacts = 0
 
int duration = 0
 
int64 end_time = 0
 
int scale = 1
 
int fillfactor = 100
 
bool unlogged_tables = false
 
double sample_rate = 0.0
 
int64 throttle_delay = 0
 
int64 latency_limit = 0
 
char * tablespace = NULL
 
char * index_tablespace = NULL
 
bool use_log
 
bool use_quiet
 
int agg_interval
 
bool per_script_stats = false
 
int progress = 0
 
bool progress_timestamp = false
 
int nclients = 1
 
int nthreads = 1
 
bool is_connect
 
bool is_latencies
 
int main_pid
 
char * pghost = ""
 
char * pgport = ""
 
char * login = NULL
 
char * dbName
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile bool timer_exceeded = false
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int num_commands = 0
 
static int64 total_weight = 0
 
static int debug = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

Referenced by ParseScript().

◆ DEFAULT_INIT_STEPS

#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */

Definition at line 93 of file pgbench.c.

Referenced by main().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 96 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 353 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

#define LOG_STEP_SECONDS   5 /* seconds between log messages */

Definition at line 95 of file pgbench.c.

Referenced by initGenerateData().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 56 of file pgbench.c.

Referenced by evalFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   10

Definition at line 360 of file pgbench.c.

Referenced by parseQuery(), process_backslash_command(), and sendCommand().

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1324 of file pgbench.c.

Referenced by evalFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 1864 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */

Definition at line 204 of file pgbench.c.

Referenced by addScript().

◆ MAXCLIENTS

#define MAXCLIENTS   1024

Definition at line 90 of file pgbench.c.

Referenced by main().

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 359 of file pgbench.c.

Referenced by doCustom(), and process_backslash_command().

◆ MIN_GAUSSIAN_PARAM

#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */

Definition at line 98 of file pgbench.c.

Referenced by evalFunc(), and getGaussianRand().

◆ naccounts

#define naccounts   100000

Definition at line 153 of file pgbench.c.

Referenced by initGenerateData().

◆ nbranches

#define nbranches
Value:
1 /* Makes little sense to change this. Change
* -s instead */

Definition at line 150 of file pgbench.c.

Referenced by initGenerateData().

◆ ntellers

#define ntellers   10

Definition at line 152 of file pgbench.c.

Referenced by initGenerateData().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ pthread_t

#define pthread_t   void *

Definition at line 79 of file pgbench.c.

Referenced by main(), and setalarm().

◆ SCALE_32BIT_THRESHOLD [1/2]

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 162 of file pgbench.c.

Referenced by initCreateTables().

◆ SCALE_32BIT_THRESHOLD [2/2]

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 162 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */

Definition at line 205 of file pgbench.c.

Referenced by runShellCommand().

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 358 of file pgbench.c.

Referenced by doCustom(), main(), process_sql_command(), and sendCommand().

◆ WSEP

#define WSEP   '@' /* weight separator */

Definition at line 184 of file pgbench.c.

Referenced by parseScriptWeight().

Typedef Documentation

◆ BuiltinScript

◆ MetaCommand

◆ ParsedScript

◆ QueryMode

◆ SimpleStats

◆ StatsData

Enumeration Type Documentation

◆ ConnectionStateEnum

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_TX 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 239 of file pgbench.c.

240 {
241  /*
242  * The client must first choose a script to execute. Once chosen, it can
243  * either be throttled (state CSTATE_START_THROTTLE under --rate) or start
244  * right away (state CSTATE_START_TX).
245  */
247 
248  /*
249  * In CSTATE_START_THROTTLE state, we calculate when to begin the next
250  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
251  * sleeps until that moment. (If throttling is not enabled, doCustom()
252  * falls directly through from CSTATE_START_THROTTLE to CSTATE_START_TX.)
253  */
256 
257  /*
258  * CSTATE_START_TX performs start-of-transaction processing. Establishes
259  * a new connection for the transaction, in --connect mode, and records
260  * the transaction start time.
261  */
263 
264  /*
265  * We loop through these states, to process each command in the script:
266  *
267  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
268  * command, the command is sent to the server, and we move to
269  * CSTATE_WAIT_RESULT state. On a \sleep meta-command, the timer is set,
270  * and we enter the CSTATE_SLEEP state to wait for it to expire. Other
271  * meta-commands are executed immediately.
272  *
273  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
274  * for the current command.
275  *
276  * CSTATE_SLEEP waits until the end of \sleep.
277  *
278  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
279  * command counter, and loops back to CSTATE_START_COMMAND state.
280  */
283  CSTATE_SLEEP,
285 
286  /*
287  * CSTATE_END_TX performs end-of-transaction processing. Calculates
288  * latency, and logs the transaction. In --connect mode, closes the
289  * current connection. Chooses the next script to execute and starts over
290  * in CSTATE_START_THROTTLE state, or enters CSTATE_FINISHED if we have no
291  * more work to do.
292  */
294 
295  /*
296  * Final states. CSTATE_ABORTED means that the script execution was
297  * aborted because a command failed, CSTATE_FINISHED means success.
298  */
ConnectionStateEnum
Definition: pgbench.c:239

◆ MetaCommand

Enumerator
META_NONE 
META_SET 
META_SETSHELL 
META_SHELL 
META_SLEEP 

Definition at line 362 of file pgbench.c.

363 {
364  META_NONE, /* not a known meta-command */
365  META_SET, /* \set */
366  META_SETSHELL, /* \setshell */
367  META_SHELL, /* \shell */
368  META_SLEEP /* \sleep */
369 } MetaCommand;
MetaCommand
Definition: pgbench.c:362

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 371 of file pgbench.c.

372 {
373  QUERY_SIMPLE, /* simple query */
374  QUERY_EXTENDED, /* extended query */
375  QUERY_PREPARED, /* extended query with prepared statements */
377 } QueryMode;
QueryMode
Definition: pgbench.c:371

Function Documentation

◆ accumStats()

static void accumStats ( StatsData stats,
bool  skipped,
double  lat,
double  lag 
)
static

Definition at line 806 of file pgbench.c.

References addToSimpleStats(), StatsData::cnt, StatsData::lag, StatsData::latency, and StatsData::skipped.

Referenced by doLog(), and processXactStats().

807 {
808  stats->cnt++;
809 
810  if (skipped)
811  {
812  /* no latency to record on skipped transactions */
813  stats->skipped++;
814  }
815  else
816  {
817  addToSimpleStats(&stats->latency, lat);
818 
819  /* and possibly the same for schedule lag */
820  if (throttle_delay)
821  addToSimpleStats(&stats->lag, lag);
822  }
823 }
SimpleStats lag
Definition: pgbench.c:233
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:762
SimpleStats latency
Definition: pgbench.c:232
int64 cnt
Definition: pgbench.c:229
int64 skipped
Definition: pgbench.c:230
int64 throttle_delay
Definition: pgbench.c:130

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 3646 of file pgbench.c.

References ParsedScript::commands, ParsedScript::desc, MAX_SCRIPTS, and num_scripts.

Referenced by ParseScript().

3647 {
3648  if (script.commands == NULL || script.commands[0] == NULL)
3649  {
3650  fprintf(stderr, "empty command list for script \"%s\"\n", script.desc);
3651  exit(1);
3652  }
3653 
3654  if (num_scripts >= MAX_SCRIPTS)
3655  {
3656  fprintf(stderr, "at most %d SQL scripts are allowed\n", MAX_SCRIPTS);
3657  exit(1);
3658  }
3659 
3660  sql_script[num_scripts] = script;
3661  num_scripts++;
3662 }
static int num_scripts
Definition: pgbench.c:403
#define MAX_SCRIPTS
Definition: pgbench.c:204
const char * desc
Definition: pgbench.c:396
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
Command ** commands
Definition: pgbench.c:398

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 762 of file pgbench.c.

References SimpleStats::count, SimpleStats::max, SimpleStats::min, SimpleStats::sum, SimpleStats::sum2, and val.

Referenced by accumStats(), and doCustom().

763 {
764  if (ss->count == 0 || val < ss->min)
765  ss->min = val;
766  if (ss->count == 0 || val > ss->max)
767  ss->max = val;
768  ss->count++;
769  ss->sum += val;
770  ss->sum2 += val * val;
771 }
double sum
Definition: pgbench.c:218
int64 count
Definition: pgbench.c:215
double max
Definition: pgbench.c:217
double sum2
Definition: pgbench.c:219
long val
Definition: informix.c:689
double min
Definition: pgbench.c:216

◆ assignVariables()

static char* assignVariables ( CState st,
char *  sql 
)
static

Definition at line 1222 of file pgbench.c.

References free, getVariable(), name, parseVariable(), replaceVariable(), and val.

Referenced by sendCommand().

1223 {
1224  char *p,
1225  *name,
1226  *val;
1227 
1228  p = sql;
1229  while ((p = strchr(p, ':')) != NULL)
1230  {
1231  int eaten;
1232 
1233  name = parseVariable(p, &eaten);
1234  if (name == NULL)
1235  {
1236  while (*p == ':')
1237  {
1238  p++;
1239  }
1240  continue;
1241  }
1242 
1243  val = getVariable(st, name);
1244  free(name);
1245  if (val == NULL)
1246  {
1247  p++;
1248  continue;
1249  }
1250 
1251  p = replaceVariable(&sql, p, eaten, val);
1252  }
1253 
1254  return sql;
1255 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:975
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1202
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1179
const char * name
Definition: encode.c:521
long val
Definition: informix.c:689

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 2968 of file pgbench.c.

Referenced by main().

2969 {
2970  const char *step;
2971 
2972  if (initialize_steps[0] == '\0')
2973  {
2974  fprintf(stderr, "no initialization steps specified\n");
2975  exit(1);
2976  }
2977 
2978  for (step = initialize_steps; *step != '\0'; step++)
2979  {
2980  if (strchr("dtgvpf ", *step) == NULL)
2981  {
2982  fprintf(stderr, "unrecognized initialization step \"%c\"\n",
2983  *step);
2984  fprintf(stderr, "allowed steps are: \"d\", \"t\", \"g\", \"v\", \"p\", \"f\"\n");
2985  exit(1);
2986  }
2987  }
2988 }

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 1881 of file pgbench.c.

References getrand(), i, and ParsedScript::weight.

Referenced by doCustom().

1882 {
1883  int i = 0;
1884  int64 w;
1885 
1886  if (num_scripts == 1)
1887  return 0;
1888 
1889  w = getrand(thread, 0, total_weight - 1);
1890  do
1891  {
1892  w -= sql_script[i++].weight;
1893  } while (w >= 0);
1894 
1895  return i - 1;
1896 }
static int64 getrand(TState *thread, int64 min, int64 max)
Definition: pgbench.c:636
static int num_scripts
Definition: pgbench.c:403
int weight
Definition: pgbench.c:397
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
static int64 total_weight
Definition: pgbench.c:405
int i

◆ coerceToDouble()

static bool coerceToDouble ( PgBenchValue pval,
double *  dval 
)
static

Definition at line 1292 of file pgbench.c.

References Assert, PgBenchValue::dval, PgBenchValue::ival, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalFunc().

1293 {
1294  if (pval->type == PGBT_DOUBLE)
1295  {
1296  *dval = pval->u.dval;
1297  return true;
1298  }
1299  else
1300  {
1301  Assert(pval->type == PGBT_INT);
1302  *dval = (double) pval->u.ival;
1303  return true;
1304  }
1305 }
union PgBenchValue::@39 u
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:670
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46

◆ coerceToInt()

static bool coerceToInt ( PgBenchValue pval,
int64 *  ival 
)
static

Definition at line 1268 of file pgbench.c.

References Assert, PgBenchValue::dval, PgBenchValue::ival, PG_INT64_MAX, PG_INT64_MIN, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalFunc().

1269 {
1270  if (pval->type == PGBT_INT)
1271  {
1272  *ival = pval->u.ival;
1273  return true;
1274  }
1275  else
1276  {
1277  double dval = pval->u.dval;
1278 
1279  Assert(pval->type == PGBT_DOUBLE);
1280  if (dval < PG_INT64_MIN || PG_INT64_MAX < dval)
1281  {
1282  fprintf(stderr, "double to int overflow for %f\n", dval);
1283  return false;
1284  }
1285  *ival = (int64) dval;
1286  return true;
1287  }
1288 }
#define PG_INT64_MAX
Definition: c.h:382
union PgBenchValue::@39 u
#define PG_INT64_MIN
Definition: c.h:381
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:670
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46

◆ commandFailed()

static void commandFailed ( CState st,
const char *  message 
)
static

Definition at line 1872 of file pgbench.c.

References CState::command, CState::id, and CState::use_file.

Referenced by doCustom().

1873 {
1874  fprintf(stderr,
1875  "client %d aborted in command %d of script %d; %s\n",
1876  st->id, st->command, st->use_file, message);
1877 }
int id
Definition: pgbench.c:309
int command
Definition: pgbench.c:313
int use_file
Definition: pgbench.c:312

◆ compareVariableNames()

static int compareVariableNames ( const void *  v1,
const void *  v2 
)
static

Definition at line 940 of file pgbench.c.

References name.

Referenced by lookupVariable().

941 {
942  return strcmp(((const Variable *) v1)->name,
943  ((const Variable *) v2)->name);
944 }
const char * name
Definition: encode.c:521

◆ discard_response()

static void discard_response ( CState state)
static

Definition at line 926 of file pgbench.c.

References CState::con, PQclear(), and PQgetResult().

Referenced by doCustom().

927 {
928  PGresult *res;
929 
930  do
931  {
932  res = PQgetResult(state->con);
933  if (res)
934  PQclear(res);
935  } while (res);
936 }
void PQclear(PGresult *res)
Definition: fe-exec.c:671
PGconn * con
Definition: pgbench.c:308
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 2622 of file pgbench.c.

References CState::con, i, length(), and PQfinish().

Referenced by main(), and threadRun().

2623 {
2624  int i;
2625 
2626  for (i = 0; i < length; i++)
2627  {
2628  if (state[i].con)
2629  {
2630  PQfinish(state[i].con);
2631  state[i].con = NULL;
2632  }
2633  }
2634 }
int length(const List *list)
Definition: list.c:1271
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3629
PGconn * con
Definition: pgbench.c:308
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 857 of file pgbench.c.

References conn, CONNECTION_BAD, dbName, have_password, login, PARAMS_ARRAY_SIZE, password, pghost, pgport, PQconnectdbParams(), PQconnectionNeedsPassword(), PQerrorMessage(), PQfinish(), PQstatus(), progname, simple_prompt(), and values.

Referenced by doCustom(), main(), runInitSteps(), and threadRun().

858 {
859  PGconn *conn;
860  bool new_pass;
861  static bool have_password = false;
862  static char password[100];
863 
864  /*
865  * Start the connection. Loop until we have a password if requested by
866  * backend.
867  */
868  do
869  {
870 #define PARAMS_ARRAY_SIZE 7
871 
872  const char *keywords[PARAMS_ARRAY_SIZE];
873  const char *values[PARAMS_ARRAY_SIZE];
874 
875  keywords[0] = "host";
876  values[0] = pghost;
877  keywords[1] = "port";
878  values[1] = pgport;
879  keywords[2] = "user";
880  values[2] = login;
881  keywords[3] = "password";
882  values[3] = have_password ? password : NULL;
883  keywords[4] = "dbname";
884  values[4] = dbName;
885  keywords[5] = "fallback_application_name";
886  values[5] = progname;
887  keywords[6] = NULL;
888  values[6] = NULL;
889 
890  new_pass = false;
891 
892  conn = PQconnectdbParams(keywords, values, true);
893 
894  if (!conn)
895  {
896  fprintf(stderr, "connection to database \"%s\" failed\n",
897  dbName);
898  return NULL;
899  }
900 
901  if (PQstatus(conn) == CONNECTION_BAD &&
903  !have_password)
904  {
905  PQfinish(conn);
906  simple_prompt("Password: ", password, sizeof(password), false);
907  have_password = true;
908  new_pass = true;
909  }
910  } while (new_pass);
911 
912  /* check to see that the backend connection was successfully made */
913  if (PQstatus(conn) == CONNECTION_BAD)
914  {
915  fprintf(stderr, "connection to database \"%s\" failed:\n%s",
916  dbName, PQerrorMessage(conn));
917  PQfinish(conn);
918  return NULL;
919  }
920 
921  return conn;
922 }
static char password[100]
Definition: streamutil.c:45
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3629
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:529
PGconn * conn
Definition: streamutil.c:46
void simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
Definition: sprompt.c:37
#define PARAMS_ARRAY_SIZE
char * pghost
Definition: pgbench.c:177
static bool have_password
Definition: streamutil.c:44
const char * progname
Definition: pgbench.c:182
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6140
char * dbName
Definition: pgbench.c:180
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6053
char * pgport
Definition: pgbench.c:178
char * login
Definition: pgbench.c:179

◆ doCustom()

static void doCustom ( TState thread,
CState st,
StatsData agg 
)
static

Definition at line 2019 of file pgbench.c.

References addToSimpleStats(), Command::argc, Command::argv, Assert, chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, TState::conn_time, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_FINISHED, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_THROTTLE, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, ParsedScript::desc, discard_response(), doConnect(), evaluateExpr(), evaluateSleep(), Command::expr, getPoissonRand(), i, CState::id, INSTR_TIME_ACCUM_DIFF, INSTR_TIME_GET_DOUBLE, INSTR_TIME_GET_MICROSEC, INSTR_TIME_IS_ZERO, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INT64_FORMAT, Command::meta, META_COMMAND, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, now(), PGRES_COMMAND_OK, PGRES_EMPTY_QUERY, PGRES_TUPLES_OK, PQclear(), PQconsumeInput(), PQerrorMessage(), PQfinish(), PQgetResult(), PQisBusy(), PQresultStatus(), CState::prepared, processXactStats(), putVariableNumber(), runShellCommand(), sendCommand(), CState::sleep_until, SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, TState::throttle_trigger, CState::txn_begin, CState::txn_scheduled, Command::type, and CState::use_file.

Referenced by threadRun().

2020 {
2021  PGresult *res;
2022  Command *command;
2023  instr_time now;
2024  bool end_tx_processed = false;
2025  int64 wait;
2026 
2027  /*
2028  * gettimeofday() isn't free, so we get the current timestamp lazily the
2029  * first time it's needed, and reuse the same value throughout this
2030  * function after that. This also ensures that e.g. the calculated
2031  * latency reported in the log file and in the totals are the same. Zero
2032  * means "not set yet". Reset "now" when we execute shell commands or
2033  * expressions, which might take a non-negligible amount of time, though.
2034  */
2035  INSTR_TIME_SET_ZERO(now);
2036 
2037  /*
2038  * Loop in the state machine, until we have to wait for a result from the
2039  * server (or have to sleep, for throttling or for \sleep).
2040  *
2041  * Note: In the switch-statement below, 'break' will loop back here,
2042  * meaning "continue in the state machine". Return is used to return to
2043  * the caller.
2044  */
2045  for (;;)
2046  {
2047  switch (st->state)
2048  {
2049  /*
2050  * Select transaction to run.
2051  */
2052  case CSTATE_CHOOSE_SCRIPT:
2053 
2054  st->use_file = chooseScript(thread);
2055 
2056  if (debug)
2057  fprintf(stderr, "client %d executing script \"%s\"\n", st->id,
2058  sql_script[st->use_file].desc);
2059 
2060  if (throttle_delay > 0)
2062  else
2063  st->state = CSTATE_START_TX;
2064  break;
2065 
2066  /*
2067  * Handle throttling once per transaction by sleeping.
2068  */
2069  case CSTATE_START_THROTTLE:
2070 
2071  /*
2072  * Generate a delay such that the series of delays will
2073  * approximate a Poisson distribution centered on the
2074  * throttle_delay time.
2075  *
2076  * If transactions are too slow or a given wait is shorter
2077  * than a transaction, the next transaction will start right
2078  * away.
2079  */
2080  Assert(throttle_delay > 0);
2081  wait = getPoissonRand(thread, throttle_delay);
2082 
2083  thread->throttle_trigger += wait;
2084  st->txn_scheduled = thread->throttle_trigger;
2085 
2086  /*
2087  * stop client if next transaction is beyond pgbench end of
2088  * execution
2089  */
2090  if (duration > 0 && st->txn_scheduled > end_time)
2091  {
2092  st->state = CSTATE_FINISHED;
2093  break;
2094  }
2095 
2096  /*
2097  * If --latency-limit is used, and this slot is already late
2098  * so that the transaction will miss the latency limit even if
2099  * it completed immediately, we skip this time slot and
2100  * iterate till the next slot that isn't late yet. But don't
2101  * iterate beyond the -t limit, if one is given.
2102  */
2103  if (latency_limit)
2104  {
2105  int64 now_us;
2106 
2107  if (INSTR_TIME_IS_ZERO(now))
2109  now_us = INSTR_TIME_GET_MICROSEC(now);
2110  while (thread->throttle_trigger < now_us - latency_limit &&
2111  (nxacts <= 0 || st->cnt < nxacts))
2112  {
2113  processXactStats(thread, st, &now, true, agg);
2114  /* next rendez-vous */
2115  wait = getPoissonRand(thread, throttle_delay);
2116  thread->throttle_trigger += wait;
2117  st->txn_scheduled = thread->throttle_trigger;
2118  }
2119  /* stop client if -t exceeded */
2120  if (nxacts > 0 && st->cnt >= nxacts)
2121  {
2122  st->state = CSTATE_FINISHED;
2123  break;
2124  }
2125  }
2126 
2127  st->state = CSTATE_THROTTLE;
2128  if (debug)
2129  fprintf(stderr, "client %d throttling " INT64_FORMAT " us\n",
2130  st->id, wait);
2131  break;
2132 
2133  /*
2134  * Wait until it's time to start next transaction.
2135  */
2136  case CSTATE_THROTTLE:
2137  if (INSTR_TIME_IS_ZERO(now))
2139  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
2140  return; /* Still sleeping, nothing to do here */
2141 
2142  /* Else done sleeping, start the transaction */
2143  st->state = CSTATE_START_TX;
2144  break;
2145 
2146  /* Start new transaction */
2147  case CSTATE_START_TX:
2148 
2149  /*
2150  * Establish connection on first call, or if is_connect is
2151  * true.
2152  */
2153  if (st->con == NULL)
2154  {
2155  instr_time start;
2156 
2157  if (INSTR_TIME_IS_ZERO(now))
2159  start = now;
2160  if ((st->con = doConnect()) == NULL)
2161  {
2162  fprintf(stderr, "client %d aborted while establishing connection\n",
2163  st->id);
2164  st->state = CSTATE_ABORTED;
2165  break;
2166  }
2168  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2169 
2170  /* Reset session-local state */
2171  memset(st->prepared, 0, sizeof(st->prepared));
2172  }
2173 
2174  /*
2175  * Record transaction start time under logging, progress or
2176  * throttling.
2177  */
2180  {
2181  if (INSTR_TIME_IS_ZERO(now))
2183  st->txn_begin = now;
2184 
2185  /*
2186  * When not throttling, this is also the transaction's
2187  * scheduled start time.
2188  */
2189  if (!throttle_delay)
2191  }
2192 
2193  /* Begin with the first command */
2194  st->command = 0;
2196  break;
2197 
2198  /*
2199  * Send a command to server (or execute a meta-command)
2200  */
2201  case CSTATE_START_COMMAND:
2202  command = sql_script[st->use_file].commands[st->command];
2203 
2204  /*
2205  * If we reached the end of the script, move to end-of-xact
2206  * processing.
2207  */
2208  if (command == NULL)
2209  {
2210  st->state = CSTATE_END_TX;
2211  break;
2212  }
2213 
2214  /*
2215  * Record statement start time if per-command latencies are
2216  * requested
2217  */
2218  if (is_latencies)
2219  {
2220  if (INSTR_TIME_IS_ZERO(now))
2222  st->stmt_begin = now;
2223  }
2224 
2225  if (command->type == SQL_COMMAND)
2226  {
2227  if (!sendCommand(st, command))
2228  {
2229  commandFailed(st, "SQL command send failed");
2230  st->state = CSTATE_ABORTED;
2231  }
2232  else
2233  st->state = CSTATE_WAIT_RESULT;
2234  }
2235  else if (command->type == META_COMMAND)
2236  {
2237  int argc = command->argc,
2238  i;
2239  char **argv = command->argv;
2240 
2241  if (debug)
2242  {
2243  fprintf(stderr, "client %d executing \\%s", st->id, argv[0]);
2244  for (i = 1; i < argc; i++)
2245  fprintf(stderr, " %s", argv[i]);
2246  fprintf(stderr, "\n");
2247  }
2248 
2249  if (command->meta == META_SLEEP)
2250  {
2251  /*
2252  * A \sleep doesn't execute anything, we just get the
2253  * delay from the argument, and enter the CSTATE_SLEEP
2254  * state. (The per-command latency will be recorded
2255  * in CSTATE_SLEEP state, not here, after the delay
2256  * has elapsed.)
2257  */
2258  int usec;
2259 
2260  if (!evaluateSleep(st, argc, argv, &usec))
2261  {
2262  commandFailed(st, "execution of meta-command 'sleep' failed");
2263  st->state = CSTATE_ABORTED;
2264  break;
2265  }
2266 
2267  if (INSTR_TIME_IS_ZERO(now))
2269  st->sleep_until = INSTR_TIME_GET_MICROSEC(now) + usec;
2270  st->state = CSTATE_SLEEP;
2271  break;
2272  }
2273  else
2274  {
2275  if (command->meta == META_SET)
2276  {
2277  PgBenchExpr *expr = command->expr;
2278  PgBenchValue result;
2279 
2280  if (!evaluateExpr(thread, st, expr, &result))
2281  {
2282  commandFailed(st, "evaluation of meta-command 'set' failed");
2283  st->state = CSTATE_ABORTED;
2284  break;
2285  }
2286 
2287  if (!putVariableNumber(st, argv[0], argv[1], &result))
2288  {
2289  commandFailed(st, "assignment of meta-command 'set' failed");
2290  st->state = CSTATE_ABORTED;
2291  break;
2292  }
2293  }
2294  else if (command->meta == META_SETSHELL)
2295  {
2296  bool ret = runShellCommand(st, argv[1], argv + 2, argc - 2);
2297 
2298  if (timer_exceeded) /* timeout */
2299  {
2300  st->state = CSTATE_FINISHED;
2301  break;
2302  }
2303  else if (!ret) /* on error */
2304  {
2305  commandFailed(st, "execution of meta-command 'setshell' failed");
2306  st->state = CSTATE_ABORTED;
2307  break;
2308  }
2309  else
2310  {
2311  /* succeeded */
2312  }
2313  }
2314  else if (command->meta == META_SHELL)
2315  {
2316  bool ret = runShellCommand(st, NULL, argv + 1, argc - 1);
2317 
2318  if (timer_exceeded) /* timeout */
2319  {
2320  st->state = CSTATE_FINISHED;
2321  break;
2322  }
2323  else if (!ret) /* on error */
2324  {
2325  commandFailed(st, "execution of meta-command 'shell' failed");
2326  st->state = CSTATE_ABORTED;
2327  break;
2328  }
2329  else
2330  {
2331  /* succeeded */
2332  }
2333  }
2334 
2335  /*
2336  * executing the expression or shell command might
2337  * take a non-negligible amount of time, so reset
2338  * 'now'
2339  */
2340  INSTR_TIME_SET_ZERO(now);
2341 
2342  st->state = CSTATE_END_COMMAND;
2343  }
2344  }
2345  break;
2346 
2347  /*
2348  * Wait for the current SQL command to complete
2349  */
2350  case CSTATE_WAIT_RESULT:
2351  command = sql_script[st->use_file].commands[st->command];
2352  if (debug)
2353  fprintf(stderr, "client %d receiving\n", st->id);
2354  if (!PQconsumeInput(st->con))
2355  { /* there's something wrong */
2356  commandFailed(st, "perhaps the backend died while processing");
2357  st->state = CSTATE_ABORTED;
2358  break;
2359  }
2360  if (PQisBusy(st->con))
2361  return; /* don't have the whole result yet */
2362 
2363  /*
2364  * Read and discard the query result;
2365  */
2366  res = PQgetResult(st->con);
2367  switch (PQresultStatus(res))
2368  {
2369  case PGRES_COMMAND_OK:
2370  case PGRES_TUPLES_OK:
2371  case PGRES_EMPTY_QUERY:
2372  /* OK */
2373  PQclear(res);
2374  discard_response(st);
2375  st->state = CSTATE_END_COMMAND;
2376  break;
2377  default:
2378  commandFailed(st, PQerrorMessage(st->con));
2379  PQclear(res);
2380  st->state = CSTATE_ABORTED;
2381  break;
2382  }
2383  break;
2384 
2385  /*
2386  * Wait until sleep is done. This state is entered after a
2387  * \sleep metacommand. The behavior is similar to
2388  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
2389  * instead of CSTATE_START_TX.
2390  */
2391  case CSTATE_SLEEP:
2392  if (INSTR_TIME_IS_ZERO(now))
2394  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
2395  return; /* Still sleeping, nothing to do here */
2396  /* Else done sleeping. */
2397  st->state = CSTATE_END_COMMAND;
2398  break;
2399 
2400  /*
2401  * End of command: record stats and proceed to next command.
2402  */
2403  case CSTATE_END_COMMAND:
2404 
2405  /*
2406  * command completed: accumulate per-command execution times
2407  * in thread-local data structure, if per-command latencies
2408  * are requested.
2409  */
2410  if (is_latencies)
2411  {
2412  if (INSTR_TIME_IS_ZERO(now))
2414 
2415  /* XXX could use a mutex here, but we choose not to */
2416  command = sql_script[st->use_file].commands[st->command];
2417  addToSimpleStats(&command->stats,
2418  INSTR_TIME_GET_DOUBLE(now) -
2420  }
2421 
2422  /* Go ahead with next command */
2423  st->command++;
2425  break;
2426 
2427  /*
2428  * End of transaction.
2429  */
2430  case CSTATE_END_TX:
2431 
2432  /* transaction finished: calculate latency and do log */
2433  processXactStats(thread, st, &now, false, agg);
2434 
2435  if (is_connect)
2436  {
2437  PQfinish(st->con);
2438  st->con = NULL;
2439  INSTR_TIME_SET_ZERO(now);
2440  }
2441 
2442  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
2443  {
2444  /* exit success */
2445  st->state = CSTATE_FINISHED;
2446  break;
2447  }
2448 
2449  /*
2450  * No transaction is underway anymore.
2451  */
2453 
2454  /*
2455  * If we paced through all commands in the script in this
2456  * loop, without returning to the caller even once, do it now.
2457  * This gives the thread a chance to process other
2458  * connections, and to do progress reporting. This can
2459  * currently only happen if the script consists entirely of
2460  * meta-commands.
2461  */
2462  if (end_tx_processed)
2463  return;
2464  else
2465  {
2466  end_tx_processed = true;
2467  break;
2468  }
2469 
2470  /*
2471  * Final states. Close the connection if it's still open.
2472  */
2473  case CSTATE_ABORTED:
2474  case CSTATE_FINISHED:
2475  if (st->con != NULL)
2476  {
2477  PQfinish(st->con);
2478  st->con = NULL;
2479  }
2480  return;
2481  }
2482  }
2483 }
static bool evaluateExpr(TState *, CState *, PgBenchExpr *, PgBenchValue *)
Definition: pgbench.c:1691
int64 throttle_trigger
Definition: pgbench.c:343
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
static bool putVariableNumber(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1141
int type
Definition: pgbench.c:386
int id
Definition: pgbench.c:309
static int chooseScript(TState *thread)
Definition: pgbench.c:1881
static void discard_response(CState *state)
Definition: pgbench.c:926
struct timeval instr_time
Definition: instr_time.h:147
PgBenchExpr * expr
Definition: pgbench.c:390
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:179
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3629
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:762
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:151
bool use_log
Definition: pgbench.c:164
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool per_script_stats
Definition: pgbench.c:168
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
char * argv[MAX_ARGS]
Definition: pgbench.c:389
int duration
Definition: pgbench.c:101
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
bool is_connect
Definition: pgbench.c:173
int64 end_time
Definition: pgbench.c:102
instr_time stmt_begin
Definition: pgbench.c:324
#define META_COMMAND
Definition: pgbench.c:359
static int debug
Definition: pgbench.c:407
static void commandFailed(CState *st, const char *message)
Definition: pgbench.c:1872
int nxacts
Definition: pgbench.c:100
const char * desc
Definition: pgbench.c:396
int64 cnt
Definition: pgbench.c:329
MetaCommand meta
Definition: pgbench.c:387
int64 txn_scheduled
Definition: pgbench.c:321
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:1900
int progress
Definition: pgbench.c:169
instr_time txn_begin
Definition: pgbench.c:323
int argc
Definition: pgbench.c:388
#define SQL_COMMAND
Definition: pgbench.c:358
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1682
int command
Definition: pgbench.c:313
SimpleStats stats
Definition: pgbench.c:391
ConnectionStateEnum state
Definition: pgbench.c:310
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:1761
static int64 getPoissonRand(TState *thread, int64 center)
Definition: pgbench.c:735
void PQclear(PGresult *res)
Definition: fe-exec.c:671
int64 sleep_until
Definition: pgbench.c:322
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:1983
PGconn * con
Definition: pgbench.c:308
static PGconn * doConnect(void)
Definition: pgbench.c:857
#define Assert(condition)
Definition: c.h:670
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1732
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
volatile bool timer_exceeded
Definition: pgbench.c:186
Command ** commands
Definition: pgbench.c:398
int64 latency_limit
Definition: pgbench.c:138
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
#define INT64_FORMAT
Definition: c.h:338
int64 throttle_delay
Definition: pgbench.c:130
int i
instr_time conn_time
Definition: pgbench.c:348
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:326
static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
Definition: pgbench.c:2575
int use_file
Definition: pgbench.c:312
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753
bool is_latencies
Definition: pgbench.c:174

◆ doLog()

static void doLog ( TState thread,
CState st,
StatsData agg,
bool  skipped,
double  latency,
double  lag 
)
static

Definition at line 2494 of file pgbench.c.

References accumStats(), Assert, StatsData::cnt, CState::cnt, gettimeofday(), CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, logfile, TState::logfile, SimpleStats::max, SimpleStats::min, pg_erand48(), TState::random_state, StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, and CState::use_file.

Referenced by processXactStats(), and threadRun().

2496 {
2497  FILE *logfile = thread->logfile;
2498 
2499  Assert(use_log);
2500 
2501  /*
2502  * Skip the log entry if sampling is enabled and this row doesn't belong
2503  * to the random sample.
2504  */
2505  if (sample_rate != 0.0 &&
2506  pg_erand48(thread->random_state) > sample_rate)
2507  return;
2508 
2509  /* should we aggregate the results or not? */
2510  if (agg_interval > 0)
2511  {
2512  /*
2513  * Loop until we reach the interval of the current moment, and print
2514  * any empty intervals in between (this may happen with very low tps,
2515  * e.g. --rate=0.1).
2516  */
2517  time_t now = time(NULL);
2518 
2519  while (agg->start_time + agg_interval <= now)
2520  {
2521  /* print aggregated report to logfile */
2522  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
2523  (long) agg->start_time,
2524  agg->cnt,
2525  agg->latency.sum,
2526  agg->latency.sum2,
2527  agg->latency.min,
2528  agg->latency.max);
2529  if (throttle_delay)
2530  {
2531  fprintf(logfile, " %.0f %.0f %.0f %.0f",
2532  agg->lag.sum,
2533  agg->lag.sum2,
2534  agg->lag.min,
2535  agg->lag.max);
2536  if (latency_limit)
2537  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
2538  }
2539  fputc('\n', logfile);
2540 
2541  /* reset data and move to next interval */
2542  initStats(agg, agg->start_time + agg_interval);
2543  }
2544 
2545  /* accumulate the current transaction */
2546  accumStats(agg, skipped, latency, lag);
2547  }
2548  else
2549  {
2550  /* no, print raw transactions */
2551  struct timeval tv;
2552 
2553  gettimeofday(&tv, NULL);
2554  if (skipped)
2555  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
2556  st->id, st->cnt, st->use_file,
2557  (long) tv.tv_sec, (long) tv.tv_usec);
2558  else
2559  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
2560  st->id, st->cnt, latency, st->use_file,
2561  (long) tv.tv_sec, (long) tv.tv_usec);
2562  if (throttle_delay)
2563  fprintf(logfile, " %.0f", lag);
2564  fputc('\n', logfile);
2565  }
2566 }
time_t start_time
Definition: pgbench.c:228
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
double sample_rate
Definition: pgbench.c:124
int id
Definition: pgbench.c:309
unsigned short random_state[3]
Definition: pgbench.c:342
SimpleStats lag
Definition: pgbench.c:233
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:793
double sum
Definition: pgbench.c:218
bool use_log
Definition: pgbench.c:164
static FILE * logfile
Definition: pg_regress.c:100
SimpleStats latency
Definition: pgbench.c:232
FILE * logfile
Definition: pgbench.c:344
int64 cnt
Definition: pgbench.c:229
int64 cnt
Definition: pgbench.c:329
int64 skipped
Definition: pgbench.c:230
double max
Definition: pgbench.c:217
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:806
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:670
double sum2
Definition: pgbench.c:219
int64 latency_limit
Definition: pgbench.c:138
#define INT64_FORMAT
Definition: c.h:338
int64 throttle_delay
Definition: pgbench.c:130
int use_file
Definition: pgbench.c:312
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534
double min
Definition: pgbench.c:216
int agg_interval
Definition: pgbench.c:166

◆ evalFunc()

static bool evalFunc ( TState thread,
CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 1330 of file pgbench.c.

References generate_unaccent_rules::args, Assert, coerceToDouble(), coerceToInt(), CState::command, PgBenchValue::dval, evaluateExpr(), getExponentialRand(), getGaussianRand(), getrand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, Min, MIN_GAUSSIAN_PARAM, PgBenchExprLink::next, PG_INT64_MIN, PGBENCH_ABS, PGBENCH_ADD, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_GREATEST, PGBENCH_INT, PGBENCH_LEAST, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_PI, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_SQRT, PGBENCH_SUB, PGBT_DOUBLE, PGBT_INT, setDoubleValue(), setIntValue(), PgBenchValue::type, generate_unaccent_rules::type, PgBenchValue::u, and CState::use_file.

Referenced by evaluateExpr().

1332 {
1333  /* evaluate all function arguments */
1334  int nargs = 0;
1335  PgBenchValue vargs[MAX_FARGS];
1336  PgBenchExprLink *l = args;
1337 
1338  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
1339  if (!evaluateExpr(thread, st, l->expr, &vargs[nargs]))
1340  return false;
1341 
1342  if (l != NULL)
1343  {
1344  fprintf(stderr,
1345  "too many function arguments, maximum is %d\n", MAX_FARGS);
1346  return false;
1347  }
1348 
1349  /* then evaluate function */
1350  switch (func)
1351  {
1352  /* overloaded operators */
1353  case PGBENCH_ADD:
1354  case PGBENCH_SUB:
1355  case PGBENCH_MUL:
1356  case PGBENCH_DIV:
1357  case PGBENCH_MOD:
1358  {
1359  PgBenchValue *lval = &vargs[0],
1360  *rval = &vargs[1];
1361 
1362  Assert(nargs == 2);
1363 
1364  /* overloaded type management, double if some double */
1365  if ((lval->type == PGBT_DOUBLE ||
1366  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
1367  {
1368  double ld,
1369  rd;
1370 
1371  if (!coerceToDouble(lval, &ld) ||
1372  !coerceToDouble(rval, &rd))
1373  return false;
1374 
1375  switch (func)
1376  {
1377  case PGBENCH_ADD:
1378  setDoubleValue(retval, ld + rd);
1379  return true;
1380 
1381  case PGBENCH_SUB:
1382  setDoubleValue(retval, ld - rd);
1383  return true;
1384 
1385  case PGBENCH_MUL:
1386  setDoubleValue(retval, ld * rd);
1387  return true;
1388 
1389  case PGBENCH_DIV:
1390  setDoubleValue(retval, ld / rd);
1391  return true;
1392 
1393  default:
1394  /* cannot get here */
1395  Assert(0);
1396  }
1397  }
1398  else /* we have integer operands, or % */
1399  {
1400  int64 li,
1401  ri;
1402 
1403  if (!coerceToInt(lval, &li) ||
1404  !coerceToInt(rval, &ri))
1405  return false;
1406 
1407  switch (func)
1408  {
1409  case PGBENCH_ADD:
1410  setIntValue(retval, li + ri);
1411  return true;
1412 
1413  case PGBENCH_SUB:
1414  setIntValue(retval, li - ri);
1415  return true;
1416 
1417  case PGBENCH_MUL:
1418  setIntValue(retval, li * ri);
1419  return true;
1420 
1421  case PGBENCH_DIV:
1422  case PGBENCH_MOD:
1423  if (ri == 0)
1424  {
1425  fprintf(stderr, "division by zero\n");
1426  return false;
1427  }
1428  /* special handling of -1 divisor */
1429  if (ri == -1)
1430  {
1431  if (func == PGBENCH_DIV)
1432  {
1433  /* overflow check (needed for INT64_MIN) */
1434  if (li == PG_INT64_MIN)
1435  {
1436  fprintf(stderr, "bigint out of range\n");
1437  return false;
1438  }
1439  else
1440  setIntValue(retval, -li);
1441  }
1442  else
1443  setIntValue(retval, 0);
1444  return true;
1445  }
1446  /* else divisor is not -1 */
1447  if (func == PGBENCH_DIV)
1448  setIntValue(retval, li / ri);
1449  else /* func == PGBENCH_MOD */
1450  setIntValue(retval, li % ri);
1451 
1452  return true;
1453 
1454  default:
1455  /* cannot get here */
1456  Assert(0);
1457  }
1458  }
1459  }
1460 
1461  /* no arguments */
1462  case PGBENCH_PI:
1463  setDoubleValue(retval, M_PI);
1464  return true;
1465 
1466  /* 1 overloaded argument */
1467  case PGBENCH_ABS:
1468  {
1469  PgBenchValue *varg = &vargs[0];
1470 
1471  Assert(nargs == 1);
1472 
1473  if (varg->type == PGBT_INT)
1474  {
1475  int64 i = varg->u.ival;
1476 
1477  setIntValue(retval, i < 0 ? -i : i);
1478  }
1479  else
1480  {
1481  double d = varg->u.dval;
1482 
1483  Assert(varg->type == PGBT_DOUBLE);
1484  setDoubleValue(retval, d < 0.0 ? -d : d);
1485  }
1486 
1487  return true;
1488  }
1489 
1490  case PGBENCH_DEBUG:
1491  {
1492  PgBenchValue *varg = &vargs[0];
1493 
1494  Assert(nargs == 1);
1495 
1496  fprintf(stderr, "debug(script=%d,command=%d): ",
1497  st->use_file, st->command + 1);
1498 
1499  if (varg->type == PGBT_INT)
1500  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
1501  else
1502  {
1503  Assert(varg->type == PGBT_DOUBLE);
1504  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
1505  }
1506 
1507  *retval = *varg;
1508 
1509  return true;
1510  }
1511 
1512  /* 1 double argument */
1513  case PGBENCH_DOUBLE:
1514  case PGBENCH_SQRT:
1515  {
1516  double dval;
1517 
1518  Assert(nargs == 1);
1519 
1520  if (!coerceToDouble(&vargs[0], &dval))
1521  return false;
1522 
1523  if (func == PGBENCH_SQRT)
1524  dval = sqrt(dval);
1525 
1526  setDoubleValue(retval, dval);
1527  return true;
1528  }
1529 
1530  /* 1 int argument */
1531  case PGBENCH_INT:
1532  {
1533  int64 ival;
1534 
1535  Assert(nargs == 1);
1536 
1537  if (!coerceToInt(&vargs[0], &ival))
1538  return false;
1539 
1540  setIntValue(retval, ival);
1541  return true;
1542  }
1543 
1544  /* variable number of arguments */
1545  case PGBENCH_LEAST:
1546  case PGBENCH_GREATEST:
1547  {
1548  bool havedouble;
1549  int i;
1550 
1551  Assert(nargs >= 1);
1552 
1553  /* need double result if any input is double */
1554  havedouble = false;
1555  for (i = 0; i < nargs; i++)
1556  {
1557  if (vargs[i].type == PGBT_DOUBLE)
1558  {
1559  havedouble = true;
1560  break;
1561  }
1562  }
1563  if (havedouble)
1564  {
1565  double extremum;
1566 
1567  if (!coerceToDouble(&vargs[0], &extremum))
1568  return false;
1569  for (i = 1; i < nargs; i++)
1570  {
1571  double dval;
1572 
1573  if (!coerceToDouble(&vargs[i], &dval))
1574  return false;
1575  if (func == PGBENCH_LEAST)
1576  extremum = Min(extremum, dval);
1577  else
1578  extremum = Max(extremum, dval);
1579  }
1580  setDoubleValue(retval, extremum);
1581  }
1582  else
1583  {
1584  int64 extremum;
1585 
1586  if (!coerceToInt(&vargs[0], &extremum))
1587  return false;
1588  for (i = 1; i < nargs; i++)
1589  {
1590  int64 ival;
1591 
1592  if (!coerceToInt(&vargs[i], &ival))
1593  return false;
1594  if (func == PGBENCH_LEAST)
1595  extremum = Min(extremum, ival);
1596  else
1597  extremum = Max(extremum, ival);
1598  }
1599  setIntValue(retval, extremum);
1600  }
1601  return true;
1602  }
1603 
1604  /* random functions */
1605  case PGBENCH_RANDOM:
1608  {
1609  int64 imin,
1610  imax;
1611 
1612  Assert(nargs >= 2);
1613 
1614  if (!coerceToInt(&vargs[0], &imin) ||
1615  !coerceToInt(&vargs[1], &imax))
1616  return false;
1617 
1618  /* check random range */
1619  if (imin > imax)
1620  {
1621  fprintf(stderr, "empty range given to random\n");
1622  return false;
1623  }
1624  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
1625  {
1626  /* prevent int overflows in random functions */
1627  fprintf(stderr, "random range is too large\n");
1628  return false;
1629  }
1630 
1631  if (func == PGBENCH_RANDOM)
1632  {
1633  Assert(nargs == 2);
1634  setIntValue(retval, getrand(thread, imin, imax));
1635  }
1636  else /* gaussian & exponential */
1637  {
1638  double param;
1639 
1640  Assert(nargs == 3);
1641 
1642  if (!coerceToDouble(&vargs[2], &param))
1643  return false;
1644 
1645  if (func == PGBENCH_RANDOM_GAUSSIAN)
1646  {
1647  if (param < MIN_GAUSSIAN_PARAM)
1648  {
1649  fprintf(stderr,
1650  "gaussian parameter must be at least %f "
1651  "(not %f)\n", MIN_GAUSSIAN_PARAM, param);
1652  return false;
1653  }
1654 
1655  setIntValue(retval,
1656  getGaussianRand(thread, imin, imax, param));
1657  }
1658  else /* exponential */
1659  {
1660  if (param <= 0.0)
1661  {
1662  fprintf(stderr,
1663  "exponential parameter must be greater than zero"
1664  " (got %f)\n", param);
1665  return false;
1666  }
1667 
1668  setIntValue(retval,
1669  getExponentialRand(thread, imin, imax, param));
1670  }
1671  }
1672 
1673  return true;
1674  }
1675 
1676  default:
1677  /* cannot get here */
1678  Assert(0);
1679  /* dead code to avoid a compiler warning */
1680  return false;
1681  }
1682 }
static bool evaluateExpr(TState *, CState *, PgBenchExpr *, PgBenchValue *)
Definition: pgbench.c:1691
static int64 getrand(TState *thread, int64 min, int64 max)
Definition: pgbench.c:636
#define Min(x, y)
Definition: c.h:802
union PgBenchValue::@39 u
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1292
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1317
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:98
static int64 getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
Definition: pgbench.c:679
#define MAX_FARGS
Definition: pgbench.c:1324
#define M_PI
Definition: pgbench.c:56
#define PG_INT64_MIN
Definition: c.h:381
int command
Definition: pgbench.c:313
double dval
Definition: pgbench.h:47
#define Max(x, y)
Definition: c.h:796
#define Assert(condition)
Definition: c.h:670
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1309
#define INT64_FORMAT
Definition: c.h:338
PgBenchValueType type
Definition: pgbench.h:43
static int64 getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
Definition: pgbench.c:656
int i
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1268
int64 ival
Definition: pgbench.h:46
int use_file
Definition: pgbench.c:312

◆ evaluateExpr()

static bool evaluateExpr ( TState thread,
CState st,
PgBenchExpr expr,
PgBenchValue retval 
)
static

Definition at line 1691 of file pgbench.c.

References PgBenchExpr::constant, ENODE_CONSTANT, ENODE_FUNCTION, ENODE_VARIABLE, PgBenchExpr::etype, evalFunc(), PgBenchExpr::function, lookupVariable(), makeVariableNumeric(), Variable::num_value, PgBenchExpr::u, and PgBenchExpr::variable.

Referenced by doCustom(), and evalFunc().

1692 {
1693  switch (expr->etype)
1694  {
1695  case ENODE_CONSTANT:
1696  {
1697  *retval = expr->u.constant;
1698  return true;
1699  }
1700 
1701  case ENODE_VARIABLE:
1702  {
1703  Variable *var;
1704 
1705  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
1706  {
1707  fprintf(stderr, "undefined variable \"%s\"\n",
1708  expr->u.variable.varname);
1709  return false;
1710  }
1711 
1712  if (!makeVariableNumeric(var))
1713  return false;
1714 
1715  *retval = var->num_value;
1716  return true;
1717  }
1718 
1719  case ENODE_FUNCTION:
1720  return evalFunc(thread, st,
1721  expr->u.function.function,
1722  expr->u.function.args,
1723  retval);
1724 
1725  default:
1726  /* internal error which should never occur */
1727  fprintf(stderr, "unexpected enode type in evaluation: %d\n",
1728  expr->etype);
1729  exit(1);
1730  }
1731 }
PgBenchValue constant
Definition: pgbench.h:90
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:948
struct PgBenchExpr::@40::@41 variable
static bool makeVariableNumeric(Variable *var)
Definition: pgbench.c:1004
static bool evalFunc(TState *thread, CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1330
PgBenchFunction function
Definition: pgbench.h:97
union PgBenchExpr::@40 u
PgBenchValue num_value
Definition: pgbench.c:201
PgBenchExprType etype
Definition: pgbench.h:87

◆ evaluateSleep()

static bool evaluateSleep ( CState st,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 1983 of file pgbench.c.

References getVariable(), and pg_strcasecmp().

Referenced by doCustom().

1984 {
1985  char *var;
1986  int usec;
1987 
1988  if (*argv[1] == ':')
1989  {
1990  if ((var = getVariable(st, argv[1] + 1)) == NULL)
1991  {
1992  fprintf(stderr, "%s: undefined variable \"%s\"\n",
1993  argv[0], argv[1]);
1994  return false;
1995  }
1996  usec = atoi(var);
1997  }
1998  else
1999  usec = atoi(argv[1]);
2000 
2001  if (argc > 2)
2002  {
2003  if (pg_strcasecmp(argv[2], "ms") == 0)
2004  usec *= 1000;
2005  else if (pg_strcasecmp(argv[2], "s") == 0)
2006  usec *= 1000000;
2007  }
2008  else
2009  usec *= 1000000;
2010 
2011  *usecs = usec;
2012  return true;
2013 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:975
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ executeStatement()

static void executeStatement ( PGconn con,
const char *  sql 
)
static

Definition at line 827 of file pgbench.c.

References PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), and PQresultStatus().

Referenced by initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateData(), and initVacuum().

828 {
829  PGresult *res;
830 
831  res = PQexec(con, sql);
832  if (PQresultStatus(res) != PGRES_COMMAND_OK)
833  {
834  fprintf(stderr, "%s", PQerrorMessage(con));
835  exit(1);
836  }
837  PQclear(res);
838 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
void PQclear(PGresult *res)
Definition: fe-exec.c:671
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897

◆ findBuiltin()

static const BuiltinScript* findBuiltin ( const char *  name)
static

Definition at line 3565 of file pgbench.c.

References i, lengthof, and listAvailableScripts().

Referenced by main().

3566 {
3567  int i,
3568  found = 0,
3569  len = strlen(name);
3570  const BuiltinScript *result = NULL;
3571 
3572  for (i = 0; i < lengthof(builtin_script); i++)
3573  {
3574  if (strncmp(builtin_script[i].name, name, len) == 0)
3575  {
3576  result = &builtin_script[i];
3577  found++;
3578  }
3579  }
3580 
3581  /* ok, unambiguous result */
3582  if (found == 1)
3583  return result;
3584 
3585  /* error cases */
3586  if (found == 0)
3587  fprintf(stderr, "no builtin script found for name \"%s\"\n", name);
3588  else /* found > 1 */
3589  fprintf(stderr,
3590  "ambiguous builtin name: %d builtin scripts found for prefix \"%s\"\n", found, name);
3591 
3593  exit(1);
3594 }
static void listAvailableScripts(void)
Definition: pgbench.c:3553
#define lengthof(array)
Definition: c.h:600
static const BuiltinScript builtin_script[]
Definition: pgbench.c:417
const char * name
Definition: encode.c:521
int i

◆ getExponentialRand()

static int64 getExponentialRand ( TState thread,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 656 of file pgbench.c.

References Assert, pg_erand48(), and TState::random_state.

Referenced by evalFunc().

657 {
658  double cut,
659  uniform,
660  rand;
661 
662  /* abort if wrong parameter, but must really be checked beforehand */
663  Assert(parameter > 0.0);
664  cut = exp(-parameter);
665  /* erand in [0, 1), uniform in (0, 1] */
666  uniform = 1.0 - pg_erand48(thread->random_state);
667 
668  /*
669  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
670  */
671  Assert((1.0 - cut) != 0.0);
672  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
673  /* return int64 random number within between min and max */
674  return min + (int64) ((max - min + 1) * rand);
675 }
unsigned short random_state[3]
Definition: pgbench.c:342
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:670

◆ getGaussianRand()

static int64 getGaussianRand ( TState thread,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 679 of file pgbench.c.

References Assert, M_PI, MIN_GAUSSIAN_PARAM, pg_erand48(), and TState::random_state.

Referenced by evalFunc().

680 {
681  double stdev;
682  double rand;
683 
684  /* abort if parameter is too low, but must really be checked beforehand */
685  Assert(parameter >= MIN_GAUSSIAN_PARAM);
686 
687  /*
688  * Get user specified random number from this loop, with -parameter <
689  * stdev <= parameter
690  *
691  * This loop is executed until the number is in the expected range.
692  *
693  * As the minimum parameter is 2.0, the probability of looping is low:
694  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
695  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
696  * the worst case. For a parameter value of 5.0, the looping probability
697  * is about e^{-5} * 2 / pi ~ 0.43%.
698  */
699  do
700  {
701  /*
702  * pg_erand48 generates [0,1), but for the basic version of the
703  * Box-Muller transform the two uniformly distributed random numbers
704  * are expected in (0, 1] (see
705  * http://en.wikipedia.org/wiki/Box_muller)
706  */
707  double rand1 = 1.0 - pg_erand48(thread->random_state);
708  double rand2 = 1.0 - pg_erand48(thread->random_state);
709 
710  /* Box-Muller basic form transform */
711  double var_sqrt = sqrt(-2.0 * log(rand1));
712 
713  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
714 
715  /*
716  * we may try with cos, but there may be a bias induced if the
717  * previous value fails the test. To be on the safe side, let us try
718  * over.
719  */
720  }
721  while (stdev < -parameter || stdev >= parameter);
722 
723  /* stdev is in [-parameter, parameter), normalization to [0,1) */
724  rand = (stdev + parameter) / (parameter * 2.0);
725 
726  /* return int64 random number within between min and max */
727  return min + (int64) ((max - min + 1) * rand);
728 }
unsigned short random_state[3]
Definition: pgbench.c:342
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:98
#define M_PI
Definition: pgbench.c:56
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:670

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 1737 of file pgbench.c.

References META_NONE, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, and pg_strcasecmp().

Referenced by process_backslash_command().

1738 {
1739  MetaCommand mc;
1740 
1741  if (cmd == NULL)
1742  mc = META_NONE;
1743  else if (pg_strcasecmp(cmd, "set") == 0)
1744  mc = META_SET;
1745  else if (pg_strcasecmp(cmd, "setshell") == 0)
1746  mc = META_SETSHELL;
1747  else if (pg_strcasecmp(cmd, "shell") == 0)
1748  mc = META_SHELL;
1749  else if (pg_strcasecmp(cmd, "sleep") == 0)
1750  mc = META_SLEEP;
1751  else
1752  mc = META_NONE;
1753  return mc;
1754 }
MetaCommand
Definition: pgbench.c:362
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ getPoissonRand()

static int64 getPoissonRand ( TState thread,
int64  center 
)
static

Definition at line 735 of file pgbench.c.

References pg_erand48(), and TState::random_state.

Referenced by doCustom().

736 {
737  /*
738  * Use inverse transform sampling to generate a value > 0, such that the
739  * expected (i.e. average) value is the given argument.
740  */
741  double uniform;
742 
743  /* erand in [0, 1), uniform in (0, 1] */
744  uniform = 1.0 - pg_erand48(thread->random_state);
745 
746  return (int64) (-log(uniform) * ((double) center) + 0.5);
747 }
unsigned short random_state[3]
Definition: pgbench.c:342
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79

◆ getQueryParams()

static void getQueryParams ( CState st,
const Command command,
const char **  params 
)
static

Definition at line 1258 of file pgbench.c.

References Command::argc, Command::argv, getVariable(), and i.

Referenced by sendCommand().

1259 {
1260  int i;
1261 
1262  for (i = 0; i < command->argc - 1; i++)
1263  params[i] = getVariable(st, command->argv[i + 1]);
1264 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:975
char * argv[MAX_ARGS]
Definition: pgbench.c:389
int argc
Definition: pgbench.c:388
int i

◆ getrand()

static int64 getrand ( TState thread,
int64  min,
int64  max 
)
static

Definition at line 636 of file pgbench.c.

References pg_erand48(), and TState::random_state.

Referenced by chooseScript(), and evalFunc().

637 {
638  /*
639  * Odd coding is so that min and max have approximately the same chance of
640  * being selected as do numbers between them.
641  *
642  * pg_erand48() is thread-safe and concurrent, which is why we use it
643  * rather than random(), which in glibc is non-reentrant, and therefore
644  * protected by a mutex, and therefore a bottleneck on machines with many
645  * CPUs.
646  */
647  return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
648 }
unsigned short random_state[3]
Definition: pgbench.c:342
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79

◆ getVariable()

static char* getVariable ( CState st,
char *  name 
)
static

Definition at line 975 of file pgbench.c.

References Assert, PgBenchValue::dval, INT64_FORMAT, Variable::is_numeric, PgBenchValue::ival, lookupVariable(), Variable::num_value, pg_strdup(), PGBT_DOUBLE, PGBT_INT, snprintf(), PgBenchValue::type, PgBenchValue::u, and Variable::value.

Referenced by assignVariables(), evaluateSleep(), getQueryParams(), and runShellCommand().

976 {
977  Variable *var;
978  char stringform[64];
979 
980  var = lookupVariable(st, name);
981  if (var == NULL)
982  return NULL; /* not found */
983 
984  if (var->value)
985  return var->value; /* we have it in string form */
986 
987  /* We need to produce a string equivalent of the numeric value */
988  Assert(var->is_numeric);
989  if (var->num_value.type == PGBT_INT)
990  snprintf(stringform, sizeof(stringform),
991  INT64_FORMAT, var->num_value.u.ival);
992  else
993  {
994  Assert(var->num_value.type == PGBT_DOUBLE);
995  snprintf(stringform, sizeof(stringform),
996  "%.*g", DBL_DIG, var->num_value.u.dval);
997  }
998  var->value = pg_strdup(stringform);
999  return var->value;
1000 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:948
union PgBenchValue::@39 u
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
bool is_numeric
Definition: pgbench.c:200
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * value
Definition: pgbench.c:199
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:670
#define INT64_FORMAT
Definition: c.h:338
const char * name
Definition: encode.c:521
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46
PgBenchValue num_value
Definition: pgbench.c:201

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 4973 of file pgbench.c.

Referenced by setalarm().

4974 {
4975  timer_exceeded = true;
4976 }
volatile bool timer_exceeded
Definition: pgbench.c:186

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 2942 of file pgbench.c.

References executeStatement(), i, and lengthof.

Referenced by runInitSteps().

2943 {
2944  static const char *const DDLKEYs[] = {
2945  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
2946  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
2947  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
2948  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
2949  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
2950  };
2951  int i;
2952 
2953  fprintf(stderr, "creating foreign keys...\n");
2954  for (i = 0; i < lengthof(DDLKEYs); i++)
2955  {
2956  executeStatement(con, DDLKEYs[i]);
2957  }
2958 }
#define lengthof(array)
Definition: c.h:600
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 2907 of file pgbench.c.

References buffer, executeStatement(), i, lengthof, PQescapeIdentifier(), PQfreemem(), snprintf(), and strlcpy().

Referenced by runInitSteps().

2908 {
2909  static const char *const DDLINDEXes[] = {
2910  "alter table pgbench_branches add primary key (bid)",
2911  "alter table pgbench_tellers add primary key (tid)",
2912  "alter table pgbench_accounts add primary key (aid)"
2913  };
2914  int i;
2915 
2916  fprintf(stderr, "creating primary keys...\n");
2917  for (i = 0; i < lengthof(DDLINDEXes); i++)
2918  {
2919  char buffer[256];
2920 
2921  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
2922 
2923  if (index_tablespace != NULL)
2924  {
2925  char *escape_tablespace;
2926 
2927  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
2928  strlen(index_tablespace));
2929  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
2930  " using index tablespace %s", escape_tablespace);
2931  PQfreemem(escape_tablespace);
2932  }
2933 
2934  executeStatement(con, buffer);
2935  }
2936 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define lengthof(array)
Definition: c.h:600
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3525
char * index_tablespace
Definition: pgbench.c:144
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
int i
void PQfreemem(void *ptr)
Definition: fe-exec.c:3251

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 2659 of file pgbench.c.

References buffer, executeStatement(), i, lengthof, PQescapeIdentifier(), PQfreemem(), SCALE_32BIT_THRESHOLD, and snprintf().

Referenced by runInitSteps().

2660 {
2661  /*
2662  * The scale factor at/beyond which 32-bit integers are insufficient for
2663  * storing TPC-B account IDs.
2664  *
2665  * Although the actual threshold is 21474, we use 20000 because it is
2666  * easier to document and remember, and isn't that far away from the real
2667  * threshold.
2668  */
2669 #define SCALE_32BIT_THRESHOLD 20000
2670 
2671  /*
2672  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
2673  * fields in these table declarations were intended to comply with that.
2674  * The pgbench_accounts table complies with that because the "filler"
2675  * column is set to blank-padded empty string. But for all other tables
2676  * the columns default to NULL and so don't actually take any space. We
2677  * could fix that by giving them non-null default values. However, that
2678  * would completely break comparability of pgbench results with prior
2679  * versions. Since pgbench has never pretended to be fully TPC-B compliant
2680  * anyway, we stick with the historical behavior.
2681  */
2682  struct ddlinfo
2683  {
2684  const char *table; /* table name */
2685  const char *smcols; /* column decls if accountIDs are 32 bits */
2686  const char *bigcols; /* column decls if accountIDs are 64 bits */
2687  int declare_fillfactor;
2688  };
2689  static const struct ddlinfo DDLs[] = {
2690  {
2691  "pgbench_history",
2692  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
2693  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
2694  0
2695  },
2696  {
2697  "pgbench_tellers",
2698  "tid int not null,bid int,tbalance int,filler char(84)",
2699  "tid int not null,bid int,tbalance int,filler char(84)",
2700  1
2701  },
2702  {
2703  "pgbench_accounts",
2704  "aid int not null,bid int,abalance int,filler char(84)",
2705  "aid bigint not null,bid int,abalance int,filler char(84)",
2706  1
2707  },
2708  {
2709  "pgbench_branches",
2710  "bid int not null,bbalance int,filler char(88)",
2711  "bid int not null,bbalance int,filler char(88)",
2712  1
2713  }
2714  };
2715  int i;
2716 
2717  fprintf(stderr, "creating tables...\n");
2718 
2719  for (i = 0; i < lengthof(DDLs); i++)
2720  {
2721  char opts[256];
2722  char buffer[256];
2723  const struct ddlinfo *ddl = &DDLs[i];
2724  const char *cols;
2725 
2726  /* Construct new create table statement. */
2727  opts[0] = '\0';
2728  if (ddl->declare_fillfactor)
2729  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
2730  " with (fillfactor=%d)", fillfactor);
2731  if (tablespace != NULL)
2732  {
2733  char *escape_tablespace;
2734 
2735  escape_tablespace = PQescapeIdentifier(con, tablespace,
2736  strlen(tablespace));
2737  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
2738  " tablespace %s", escape_tablespace);
2739  PQfreemem(escape_tablespace);
2740  }
2741 
2742  cols = (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols;
2743 
2744  snprintf(buffer, sizeof(buffer), "create%s table %s(%s)%s",
2745  unlogged_tables ? " unlogged" : "",
2746  ddl->table, cols, opts);
2747 
2748  executeStatement(con, buffer);
2749  }
2750 }
int scale
Definition: pgbench.c:108
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define lengthof(array)
Definition: c.h:600
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:162
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3525
int fillfactor
Definition: pgbench.c:114
char * tablespace
Definition: pgbench.c:143
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
bool unlogged_tables
Definition: pgbench.c:119
int i
void PQfreemem(void *ptr)
Definition: fe-exec.c:3251

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 2640 of file pgbench.c.

References executeStatement().

Referenced by runInitSteps().

2641 {
2642  fprintf(stderr, "dropping old tables...\n");
2643 
2644  /*
2645  * We drop all the tables in one command, so that whether there are
2646  * foreign key dependencies or not doesn't matter.
2647  */
2648  executeStatement(con, "drop table if exists "
2649  "pgbench_accounts, "
2650  "pgbench_branches, "
2651  "pgbench_history, "
2652  "pgbench_tellers");
2653 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827

◆ initGenerateData()

static void initGenerateData ( PGconn con)
static

Definition at line 2756 of file pgbench.c.

References executeStatement(), i, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64_FORMAT, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), scale, and snprintf().

Referenced by runInitSteps().

2757 {
2758  char sql[256];
2759  PGresult *res;
2760  int i;
2761  int64 k;
2762 
2763  /* used to track elapsed time and estimate of the remaining time */
2764  instr_time start,
2765  diff;
2766  double elapsed_sec,
2767  remaining_sec;
2768  int log_interval = 1;
2769 
2770  fprintf(stderr, "generating data...\n");
2771 
2772  /*
2773  * we do all of this in one transaction to enable the backend's
2774  * data-loading optimizations
2775  */
2776  executeStatement(con, "begin");
2777 
2778  /*
2779  * truncate away any old data, in one command in case there are foreign
2780  * keys
2781  */
2782  executeStatement(con, "truncate table "
2783  "pgbench_accounts, "
2784  "pgbench_branches, "
2785  "pgbench_history, "
2786  "pgbench_tellers");
2787 
2788  /*
2789  * fill branches, tellers, accounts in that order in case foreign keys
2790  * already exist
2791  */
2792  for (i = 0; i < nbranches * scale; i++)
2793  {
2794  /* "filler" column defaults to NULL */
2795  snprintf(sql, sizeof(sql),
2796  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
2797  i + 1);
2798  executeStatement(con, sql);
2799  }
2800 
2801  for (i = 0; i < ntellers * scale; i++)
2802  {
2803  /* "filler" column defaults to NULL */
2804  snprintf(sql, sizeof(sql),
2805  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
2806  i + 1, i / ntellers + 1);
2807  executeStatement(con, sql);
2808  }
2809 
2810  /*
2811  * accounts is big enough to be worth using COPY and tracking runtime
2812  */
2813  res = PQexec(con, "copy pgbench_accounts from stdin");
2814  if (PQresultStatus(res) != PGRES_COPY_IN)
2815  {
2816  fprintf(stderr, "%s", PQerrorMessage(con));
2817  exit(1);
2818  }
2819  PQclear(res);
2820 
2821  INSTR_TIME_SET_CURRENT(start);
2822 
2823  for (k = 0; k < (int64) naccounts * scale; k++)
2824  {
2825  int64 j = k + 1;
2826 
2827  /* "filler" column defaults to blank padded empty string */
2828  snprintf(sql, sizeof(sql),
2829  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
2830  j, k / naccounts + 1, 0);
2831  if (PQputline(con, sql))
2832  {
2833  fprintf(stderr, "PQputline failed\n");
2834  exit(1);
2835  }
2836 
2837  /*
2838  * If we want to stick with the original logging, print a message each
2839  * 100k inserted rows.
2840  */
2841  if ((!use_quiet) && (j % 100000 == 0))
2842  {
2843  INSTR_TIME_SET_CURRENT(diff);
2844  INSTR_TIME_SUBTRACT(diff, start);
2845 
2846  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
2847  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
2848 
2849  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
2850  j, (int64) naccounts * scale,
2851  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
2852  elapsed_sec, remaining_sec);
2853  }
2854  /* let's not call the timing for each row, but only each 100 rows */
2855  else if (use_quiet && (j % 100 == 0))
2856  {
2857  INSTR_TIME_SET_CURRENT(diff);
2858  INSTR_TIME_SUBTRACT(diff, start);
2859 
2860  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
2861  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
2862 
2863  /* have we reached the next interval (or end)? */
2864  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
2865  {
2866  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
2867  j, (int64) naccounts * scale,
2868  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec);
2869 
2870  /* skip to the next interval */
2871  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
2872  }
2873  }
2874 
2875  }
2876  if (PQputline(con, "\\.\n"))
2877  {
2878  fprintf(stderr, "very last PQputline failed\n");
2879  exit(1);
2880  }
2881  if (PQendcopy(con))
2882  {
2883  fprintf(stderr, "PQendcopy failed\n");
2884  exit(1);
2885  }
2886 
2887  executeStatement(con, "commit");
2888 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
struct timeval instr_time
Definition: instr_time.h:147
int scale
Definition: pgbench.c:108
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
#define LOG_STEP_SECONDS
Definition: pgbench.c:95
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
bool use_quiet
Definition: pgbench.c:165
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2540
#define nbranches
Definition: pgbench.c:150
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
#define ntellers
Definition: pgbench.c:152
#define naccounts
Definition: pgbench.c:153
void PQclear(PGresult *res)
Definition: fe-exec.c:671
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2573
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
#define INT64_FORMAT
Definition: c.h:338
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 753 of file pgbench.c.

Referenced by initStats(), process_backslash_command(), and process_sql_command().

754 {
755  memset(ss, 0, sizeof(SimpleStats));
756 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 793 of file pgbench.c.

References StatsData::cnt, initSimpleStats(), StatsData::lag, StatsData::latency, StatsData::skipped, start_time, and StatsData::start_time.

Referenced by doLog(), main(), ParseScript(), and threadRun().

794 {
795  sd->start_time = start_time;
796  sd->cnt = 0;
797  sd->skipped = 0;
798  initSimpleStats(&sd->latency);
799  initSimpleStats(&sd->lag);
800 }
time_t start_time
Definition: pgbench.c:228
SimpleStats lag
Definition: pgbench.c:233
SimpleStats latency
Definition: pgbench.c:232
static time_t start_time
Definition: pg_ctl.c:95
int64 cnt
Definition: pgbench.c:229
int64 skipped
Definition: pgbench.c:230
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:753

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 2894 of file pgbench.c.

References executeStatement().

Referenced by runInitSteps().

2895 {
2896  fprintf(stderr, "vacuuming...\n");
2897  executeStatement(con, "vacuum analyze pgbench_branches");
2898  executeStatement(con, "vacuum analyze pgbench_tellers");
2899  executeStatement(con, "vacuum analyze pgbench_accounts");
2900  executeStatement(con, "vacuum analyze pgbench_history");
2901 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:827

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 541 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableNumeric().

542 {
543  const char *ptr = str;
544 
545  /* skip leading spaces; cast is consistent with strtoint64 */
546  while (*ptr && isspace((unsigned char) *ptr))
547  ptr++;
548 
549  /* skip sign */
550  if (*ptr == '+' || *ptr == '-')
551  ptr++;
552 
553  /* at least one digit */
554  if (*ptr && !isdigit((unsigned char) *ptr))
555  return false;
556 
557  /* eat all digits */
558  while (*ptr && isdigit((unsigned char) *ptr))
559  ptr++;
560 
561  /* must have reached end of string */
562  return *ptr == '\0';
563 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 3553 of file pgbench.c.

References i, lengthof, and name.

Referenced by findBuiltin(), and main().

3554 {
3555  int i;
3556 
3557  fprintf(stderr, "Available builtin scripts:\n");
3558  for (i = 0; i < lengthof(builtin_script); i++)
3559  fprintf(stderr, "\t%s\n", builtin_script[i].name);
3560  fprintf(stderr, "\n");
3561 }
#define lengthof(array)
Definition: c.h:600
static const BuiltinScript builtin_script[]
Definition: pgbench.c:417
const char * name
Definition: encode.c:521
int i

◆ lookupCreateVariable()

static Variable* lookupCreateVariable ( CState st,
const char *  context,
char *  name 
)
static

Definition at line 1072 of file pgbench.c.

References lookupVariable(), Variable::name, CState::nvariables, pg_malloc(), pg_realloc(), pg_strdup(), valid_variable_name(), Variable::value, CState::variables, and CState::vars_sorted.

Referenced by putVariable(), and putVariableNumber().

1073 {
1074  Variable *var;
1075 
1076  var = lookupVariable(st, name);
1077  if (var == NULL)
1078  {
1079  Variable *newvars;
1080 
1081  /*
1082  * Check for the name only when declaring a new variable to avoid
1083  * overhead.
1084  */
1085  if (!valid_variable_name(name))
1086  {
1087  fprintf(stderr, "%s: invalid variable name: \"%s\"\n",
1088  context, name);
1089  return NULL;
1090  }
1091 
1092  /* Create variable at the end of the array */
1093  if (st->variables)
1094  newvars = (Variable *) pg_realloc(st->variables,
1095  (st->nvariables + 1) * sizeof(Variable));
1096  else
1097  newvars = (Variable *) pg_malloc(sizeof(Variable));
1098 
1099  st->variables = newvars;
1100 
1101  var = &newvars[st->nvariables];
1102 
1103  var->name = pg_strdup(name);
1104  var->value = NULL;
1105  /* caller is expected to initialize remaining fields */
1106 
1107  st->nvariables++;
1108  /* we don't re-sort the array till we have to */
1109  st->vars_sorted = false;
1110  }
1111 
1112  return var;
1113 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:948
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:198
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1045
Variable * variables
Definition: pgbench.c:316
bool vars_sorted
Definition: pgbench.c:318
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
char * value
Definition: pgbench.c:199
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:317

◆ lookupVariable()

static Variable* lookupVariable ( CState st,
char *  name 
)
static

Definition at line 948 of file pgbench.c.

References compareVariableNames(), Variable::name, name, CState::nvariables, qsort, CState::variables, and CState::vars_sorted.

Referenced by evaluateExpr(), getVariable(), lookupCreateVariable(), and main().

949 {
950  Variable key;
951 
952  /* On some versions of Solaris, bsearch of zero items dumps core */
953  if (st->nvariables <= 0)
954  return NULL;
955 
956  /* Sort if we have to */
957  if (!st->vars_sorted)
958  {
959  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
961  st->vars_sorted = true;
962  }
963 
964  /* Now we can search */
965  key.name = name;
966  return (Variable *) bsearch((void *) &key,
967  (void *) st->variables,
968  st->nvariables,
969  sizeof(Variable),
971 }
char * name
Definition: pgbench.c:198
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:940
Variable * variables
Definition: pgbench.c:316
bool vars_sorted
Definition: pgbench.c:318
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:317
#define qsort(a, b, c, d)
Definition: port.h:408

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 3796 of file pgbench.c.

References _, Assert, checkInitSteps(), StatsData::cnt, ParsedScript::commands, TState::conn_time, CONNECTION_BAD, DEFAULT_INIT_STEPS, DEFAULT_NXACTS, disconnect_all(), doConnect(), ERRCODE_UNDEFINED_TABLE, findBuiltin(), get_progname(), getopt_long(), i, CState::id, initStats(), INSTR_TIME_ADD, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INSTR_TIME_SUBTRACT, INVALID_THREAD, Variable::is_numeric, StatsData::lag, StatsData::latency, TState::latency_late, listAvailableScripts(), TState::logfile, login, lookupVariable(), MAXCLIENTS, mergeSimpleStats(), Variable::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, Variable::num_value, CState::nvariables, optarg, optind, parseQuery(), parseScriptWeight(), PG_DIAG_SQLSTATE, pg_free(), pg_malloc(), pg_realloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQfinish(), PQgetvalue(), PQresultErrorField(), PQresultStatus(), PQstatus(), printResults(), process_builtin(), process_file(), putVariable(), putVariableInt(), putVariableNumber(), QUERY_SIMPLE, random(), TState::random_state, required_argument, runInitSteps(), setalarm(), StatsData::skipped, SQL_COMMAND, srandom(), start_time, TState::start_time, TState::state, TState::stats, strerror(), TState::thread, threadRun(), TState::tid, tryExecuteStatement(), generate_unaccent_rules::type, usage(), Variable::value, and CState::variables.

3797 {
3798  static struct option long_options[] = {
3799  /* systematic long/short named options */
3800  {"builtin", required_argument, NULL, 'b'},
3801  {"client", required_argument, NULL, 'c'},
3802  {"connect", no_argument, NULL, 'C'},
3803  {"debug", no_argument, NULL, 'd'},
3804  {"define", required_argument, NULL, 'D'},
3805  {"file", required_argument, NULL, 'f'},
3806  {"fillfactor", required_argument, NULL, 'F'},
3807  {"host", required_argument, NULL, 'h'},
3808  {"initialize", no_argument, NULL, 'i'},
3809  {"init-steps", required_argument, NULL, 'I'},
3810  {"jobs", required_argument, NULL, 'j'},
3811  {"log", no_argument, NULL, 'l'},
3812  {"latency-limit", required_argument, NULL, 'L'},
3813  {"no-vacuum", no_argument, NULL, 'n'},
3814  {"port", required_argument, NULL, 'p'},
3815  {"progress", required_argument, NULL, 'P'},
3816  {"protocol", required_argument, NULL, 'M'},
3817  {"quiet", no_argument, NULL, 'q'},
3818  {"report-latencies", no_argument, NULL, 'r'},
3819  {"rate", required_argument, NULL, 'R'},
3820  {"scale", required_argument, NULL, 's'},
3821  {"select-only", no_argument, NULL, 'S'},
3822  {"skip-some-updates", no_argument, NULL, 'N'},
3823  {"time", required_argument, NULL, 'T'},
3824  {"transactions", required_argument, NULL, 't'},
3825  {"username", required_argument, NULL, 'U'},
3826  {"vacuum-all", no_argument, NULL, 'v'},
3827  /* long-named only options */
3828  {"unlogged-tables", no_argument, NULL, 1},
3829  {"tablespace", required_argument, NULL, 2},
3830  {"index-tablespace", required_argument, NULL, 3},
3831  {"sampling-rate", required_argument, NULL, 4},
3832  {"aggregate-interval", required_argument, NULL, 5},
3833  {"progress-timestamp", no_argument, NULL, 6},
3834  {"log-prefix", required_argument, NULL, 7},
3835  {"foreign-keys", no_argument, NULL, 8},
3836  {NULL, 0, NULL, 0}
3837  };
3838 
3839  int c;
3840  bool is_init_mode = false; /* initialize mode? */
3841  char *initialize_steps = NULL;
3842  bool foreign_keys = false;
3843  bool is_no_vacuum = false;
3844  bool do_vacuum_accounts = false; /* vacuum accounts table? */
3845  int optindex;
3846  bool scale_given = false;
3847 
3848  bool benchmarking_option_set = false;
3849  bool initialization_option_set = false;
3850  bool internal_script_used = false;
3851 
3852  CState *state; /* status of clients */
3853  TState *threads; /* array of thread */
3854 
3855  instr_time start_time; /* start up time */
3856  instr_time total_time;
3857  instr_time conn_total_time;
3858  int64 latency_late = 0;
3859  StatsData stats;
3860  int weight;
3861 
3862  int i;
3863  int nclients_dealt;
3864 
3865 #ifdef HAVE_GETRLIMIT
3866  struct rlimit rlim;
3867 #endif
3868 
3869  PGconn *con;
3870  PGresult *res;
3871  char *env;
3872 
3873  progname = get_progname(argv[0]);
3874 
3875  if (argc > 1)
3876  {
3877  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
3878  {
3879  usage();
3880  exit(0);
3881  }
3882  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
3883  {
3884  puts("pgbench (PostgreSQL) " PG_VERSION);
3885  exit(0);
3886  }
3887  }
3888 
3889 #ifdef WIN32
3890  /* stderr is buffered on Win32. */
3891  setvbuf(stderr, NULL, _IONBF, 0);
3892 #endif
3893 
3894  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
3895  pghost = env;
3896  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
3897  pgport = env;
3898  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
3899  login = env;
3900 
3901  state = (CState *) pg_malloc(sizeof(CState));
3902  memset(state, 0, sizeof(CState));
3903 
3904  while ((c = getopt_long(argc, argv, "iI:h:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
3905  {
3906  char *script;
3907 
3908  switch (c)
3909  {
3910  case 'i':
3911  is_init_mode = true;
3912  break;
3913  case 'I':
3914  if (initialize_steps)
3915  pg_free(initialize_steps);
3916  initialize_steps = pg_strdup(optarg);
3917  checkInitSteps(initialize_steps);
3918  initialization_option_set = true;
3919  break;
3920  case 'h':
3921  pghost = pg_strdup(optarg);
3922  break;
3923  case 'n':
3924  is_no_vacuum = true;
3925  break;
3926  case 'v':
3927  benchmarking_option_set = true;
3928  do_vacuum_accounts = true;
3929  break;
3930  case 'p':
3931  pgport = pg_strdup(optarg);
3932  break;
3933  case 'd':
3934  debug++;
3935  break;
3936  case 'c':
3937  benchmarking_option_set = true;
3938  nclients = atoi(optarg);
3939  if (nclients <= 0 || nclients > MAXCLIENTS)
3940  {
3941  fprintf(stderr, "invalid number of clients: \"%s\"\n",
3942  optarg);
3943  exit(1);
3944  }
3945 #ifdef HAVE_GETRLIMIT
3946 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
3947  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
3948 #else /* but BSD doesn't ... */
3949  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
3950 #endif /* RLIMIT_NOFILE */
3951  {
3952  fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
3953  exit(1);
3954  }
3955  if (rlim.rlim_cur < nclients + 3)
3956  {
3957  fprintf(stderr, "need at least %d open files, but system limit is %ld\n",
3958  nclients + 3, (long) rlim.rlim_cur);
3959  fprintf(stderr, "Reduce number of clients, or use limit/ulimit to increase the system limit.\n");
3960  exit(1);
3961  }
3962 #endif /* HAVE_GETRLIMIT */
3963  break;
3964  case 'j': /* jobs */
3965  benchmarking_option_set = true;
3966  nthreads = atoi(optarg);
3967  if (nthreads <= 0)
3968  {
3969  fprintf(stderr, "invalid number of threads: \"%s\"\n",
3970  optarg);
3971  exit(1);
3972  }
3973 #ifndef ENABLE_THREAD_SAFETY
3974  if (nthreads != 1)
3975  {
3976  fprintf(stderr, "threads are not supported on this platform; use -j1\n");
3977  exit(1);
3978  }
3979 #endif /* !ENABLE_THREAD_SAFETY */
3980  break;
3981  case 'C':
3982  benchmarking_option_set = true;
3983  is_connect = true;
3984  break;
3985  case 'r':
3986  benchmarking_option_set = true;
3987  per_script_stats = true;
3988  is_latencies = true;
3989  break;
3990  case 's':
3991  scale_given = true;
3992  scale = atoi(optarg);
3993  if (scale <= 0)
3994  {
3995  fprintf(stderr, "invalid scaling factor: \"%s\"\n", optarg);
3996  exit(1);
3997  }
3998  break;
3999  case 't':
4000  benchmarking_option_set = true;
4001  nxacts = atoi(optarg);
4002  if (nxacts <= 0)
4003  {
4004  fprintf(stderr, "invalid number of transactions: \"%s\"\n",
4005  optarg);
4006  exit(1);
4007  }
4008  break;
4009  case 'T':
4010  benchmarking_option_set = true;
4011  duration = atoi(optarg);
4012  if (duration <= 0)
4013  {
4014  fprintf(stderr, "invalid duration: \"%s\"\n", optarg);
4015  exit(1);
4016  }
4017  break;
4018  case 'U':
4019  login = pg_strdup(optarg);
4020  break;
4021  case 'l':
4022  benchmarking_option_set = true;
4023  use_log = true;
4024  break;
4025  case 'q':
4026  initialization_option_set = true;
4027  use_quiet = true;
4028  break;
4029  case 'b':
4030  if (strcmp(optarg, "list") == 0)
4031  {
4033  exit(0);
4034  }
4035  weight = parseScriptWeight(optarg, &script);
4036  process_builtin(findBuiltin(script), weight);
4037  benchmarking_option_set = true;
4038  internal_script_used = true;
4039  break;
4040  case 'S':
4041  process_builtin(findBuiltin("select-only"), 1);
4042  benchmarking_option_set = true;
4043  internal_script_used = true;
4044  break;
4045  case 'N':
4046  process_builtin(findBuiltin("simple-update"), 1);
4047  benchmarking_option_set = true;
4048  internal_script_used = true;
4049  break;
4050  case 'f':
4051  weight = parseScriptWeight(optarg, &script);
4052  process_file(script, weight);
4053  benchmarking_option_set = true;
4054  break;
4055  case 'D':
4056  {
4057  char *p;
4058 
4059  benchmarking_option_set = true;
4060 
4061  if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
4062  {
4063  fprintf(stderr, "invalid variable definition: \"%s\"\n",
4064  optarg);
4065  exit(1);
4066  }
4067 
4068  *p++ = '\0';
4069  if (!putVariable(&state[0], "option", optarg, p))
4070  exit(1);
4071  }
4072  break;
4073  case 'F':
4074  initialization_option_set = true;
4075  fillfactor = atoi(optarg);
4076  if (fillfactor < 10 || fillfactor > 100)
4077  {
4078  fprintf(stderr, "invalid fillfactor: \"%s\"\n", optarg);
4079  exit(1);
4080  }
4081  break;
4082  case 'M':
4083  benchmarking_option_set = true;
4084  for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
4085  if (strcmp(optarg, QUERYMODE[querymode]) == 0)
4086  break;
4087  if (querymode >= NUM_QUERYMODE)
4088  {
4089  fprintf(stderr, "invalid query mode (-M): \"%s\"\n",
4090  optarg);
4091  exit(1);
4092  }
4093  break;
4094  case 'P':
4095  benchmarking_option_set = true;
4096  progress = atoi(optarg);
4097  if (progress <= 0)
4098  {
4099  fprintf(stderr, "invalid thread progress delay: \"%s\"\n",
4100  optarg);
4101  exit(1);
4102  }
4103  break;
4104  case 'R':
4105  {
4106  /* get a double from the beginning of option value */
4107  double throttle_value = atof(optarg);
4108 
4109  benchmarking_option_set = true;
4110 
4111  if (throttle_value <= 0.0)
4112  {
4113  fprintf(stderr, "invalid rate limit: \"%s\"\n", optarg);
4114  exit(1);
4115  }
4116  /* Invert rate limit into a time offset */
4117  throttle_delay = (int64) (1000000.0 / throttle_value);
4118  }
4119  break;
4120  case 'L':
4121  {
4122  double limit_ms = atof(optarg);
4123 
4124  if (limit_ms <= 0.0)
4125  {
4126  fprintf(stderr, "invalid latency limit: \"%s\"\n",
4127  optarg);
4128  exit(1);
4129  }
4130  benchmarking_option_set = true;
4131  latency_limit = (int64) (limit_ms * 1000);
4132  }
4133  break;
4134  case 1: /* unlogged-tables */
4135  initialization_option_set = true;
4136  unlogged_tables = true;
4137  break;
4138  case 2: /* tablespace */
4139  initialization_option_set = true;
4141  break;
4142  case 3: /* index-tablespace */
4143  initialization_option_set = true;
4145  break;
4146  case 4: /* sampling-rate */
4147  benchmarking_option_set = true;
4148  sample_rate = atof(optarg);
4149  if (sample_rate <= 0.0 || sample_rate > 1.0)
4150  {
4151  fprintf(stderr, "invalid sampling rate: \"%s\"\n", optarg);
4152  exit(1);
4153  }
4154  break;
4155  case 5: /* aggregate-interval */
4156  benchmarking_option_set = true;
4157  agg_interval = atoi(optarg);
4158  if (agg_interval <= 0)
4159  {
4160  fprintf(stderr, "invalid number of seconds for aggregation: \"%s\"\n",
4161  optarg);
4162  exit(1);
4163  }
4164  break;
4165  case 6: /* progress-timestamp */
4166  progress_timestamp = true;
4167  benchmarking_option_set = true;
4168  break;
4169  case 7: /* log-prefix */
4170  benchmarking_option_set = true;
4172  break;
4173  case 8: /* foreign-keys */
4174  initialization_option_set = true;
4175  foreign_keys = true;
4176  break;
4177  default:
4178  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
4179  exit(1);
4180  break;
4181  }
4182  }
4183 
4184  /* set default script if none */
4185  if (num_scripts == 0 && !is_init_mode)
4186  {
4187  process_builtin(findBuiltin("tpcb-like"), 1);
4188  benchmarking_option_set = true;
4189  internal_script_used = true;
4190  }
4191 
4192  /* if not simple query mode, parse the script(s) to find parameters */
4193  if (querymode != QUERY_SIMPLE)
4194  {
4195  for (i = 0; i < num_scripts; i++)
4196  {
4197  Command **commands = sql_script[i].commands;
4198  int j;
4199 
4200  for (j = 0; commands[j] != NULL; j++)
4201  {
4202  if (commands[j]->type != SQL_COMMAND)
4203  continue;
4204  if (!parseQuery(commands[j]))
4205  exit(1);
4206  }
4207  }
4208  }
4209 
4210  /* compute total_weight */
4211  for (i = 0; i < num_scripts; i++)
4212  /* cannot overflow: weight is 32b, total_weight 64b */
4213  total_weight += sql_script[i].weight;
4214 
4215  if (total_weight == 0 && !is_init_mode)
4216  {
4217  fprintf(stderr, "total script weight must not be zero\n");
4218  exit(1);
4219  }
4220 
4221  /* show per script stats if several scripts are used */
4222  if (num_scripts > 1)
4223  per_script_stats = true;
4224 
4225  /*
4226  * Don't need more threads than there are clients. (This is not merely an
4227  * optimization; throttle_delay is calculated incorrectly below if some
4228  * threads have no clients assigned to them.)
4229  */
4230  if (nthreads > nclients)
4231  nthreads = nclients;
4232 
4233  /* compute a per thread delay */
4235 
4236  if (argc > optind)
4237  dbName = argv[optind];
4238  else
4239  {
4240  if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
4241  dbName = env;
4242  else if (login != NULL && *login != '\0')
4243  dbName = login;
4244  else
4245  dbName = "";
4246  }
4247 
4248  if (is_init_mode)
4249  {
4250  if (benchmarking_option_set)
4251  {
4252  fprintf(stderr, "some of the specified options cannot be used in initialization (-i) mode\n");
4253  exit(1);
4254  }
4255 
4256  if (initialize_steps == NULL)
4257  initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
4258 
4259  if (is_no_vacuum)
4260  {
4261  /* Remove any vacuum step in initialize_steps */
4262  char *p;
4263 
4264  while ((p = strchr(initialize_steps, 'v')) != NULL)
4265  *p = ' ';
4266  }
4267 
4268  if (foreign_keys)
4269  {
4270  /* Add 'f' to end of initialize_steps, if not already there */
4271  if (strchr(initialize_steps, 'f') == NULL)
4272  {
4273  initialize_steps = (char *)
4274  pg_realloc(initialize_steps,
4275  strlen(initialize_steps) + 2);
4276  strcat(initialize_steps, "f");
4277  }
4278  }
4279 
4280  runInitSteps(initialize_steps);
4281  exit(0);
4282  }
4283  else
4284  {
4285  if (initialization_option_set)
4286  {
4287  fprintf(stderr, "some of the specified options cannot be used in benchmarking mode\n");
4288  exit(1);
4289  }
4290  }
4291 
4292  if (nxacts > 0 && duration > 0)
4293  {
4294  fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both\n");
4295  exit(1);
4296  }
4297 
4298  /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
4299  if (nxacts <= 0 && duration <= 0)
4301 
4302  /* --sampling-rate may be used only with -l */
4303  if (sample_rate > 0.0 && !use_log)
4304  {
4305  fprintf(stderr, "log sampling (--sampling-rate) is allowed only when logging transactions (-l)\n");
4306  exit(1);
4307  }
4308 
4309  /* --sampling-rate may not be used with --aggregate-interval */
4310  if (sample_rate > 0.0 && agg_interval > 0)
4311  {
4312  fprintf(stderr, "log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time\n");
4313  exit(1);
4314  }
4315 
4316  if (agg_interval > 0 && !use_log)
4317  {
4318  fprintf(stderr, "log aggregation is allowed only when actually logging transactions\n");
4319  exit(1);
4320  }
4321 
4322  if (!use_log && logfile_prefix)
4323  {
4324  fprintf(stderr, "log file prefix (--log-prefix) is allowed only when logging transactions (-l)\n");
4325  exit(1);
4326  }
4327 
4328  if (duration > 0 && agg_interval > duration)
4329  {
4330  fprintf(stderr, "number of seconds for aggregation (%d) must not be higher than test duration (%d)\n", agg_interval, duration);
4331  exit(1);
4332  }
4333 
4334  if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
4335  {
4336  fprintf(stderr, "duration (%d) must be a multiple of aggregation interval (%d)\n", duration, agg_interval);
4337  exit(1);
4338  }
4339 
4340  if (progress_timestamp && progress == 0)
4341  {
4342  fprintf(stderr, "--progress-timestamp is allowed only under --progress\n");
4343  exit(1);
4344  }
4345 
4346  /*
4347  * save main process id in the global variable because process id will be
4348  * changed after fork.
4349  */
4350  main_pid = (int) getpid();
4351 
4352  if (nclients > 1)
4353  {
4354  state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
4355  memset(state + 1, 0, sizeof(CState) * (nclients - 1));
4356 
4357  /* copy any -D switch values to all clients */
4358  for (i = 1; i < nclients; i++)
4359  {
4360  int j;
4361 
4362  state[i].id = i;
4363  for (j = 0; j < state[0].nvariables; j++)
4364  {
4365  Variable *var = &state[0].variables[j];
4366 
4367  if (var->is_numeric)
4368  {
4369  if (!putVariableNumber(&state[i], "startup",
4370  var->name, &var->num_value))
4371  exit(1);
4372  }
4373  else
4374  {
4375  if (!putVariable(&state[i], "startup",
4376  var->name, var->value))
4377  exit(1);
4378  }
4379  }
4380  }
4381  }
4382 
4383  if (debug)
4384  {
4385  if (duration <= 0)
4386  printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
4387  pghost, pgport, nclients, nxacts, dbName);
4388  else
4389  printf("pghost: %s pgport: %s nclients: %d duration: %d dbName: %s\n",
4390  pghost, pgport, nclients, duration, dbName);
4391  }
4392 
4393  /* opening connection... */
4394  con = doConnect();
4395  if (con == NULL)
4396  exit(1);
4397 
4398  if (PQstatus(con) == CONNECTION_BAD)
4399  {
4400  fprintf(stderr, "connection to database \"%s\" failed\n", dbName);
4401  fprintf(stderr, "%s", PQerrorMessage(con));
4402  exit(1);
4403  }
4404 
4405  if (internal_script_used)
4406  {
4407  /*
4408  * get the scaling factor that should be same as count(*) from
4409  * pgbench_branches if this is not a custom query
4410  */
4411  res = PQexec(con, "select count(*) from pgbench_branches");
4412  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4413  {
4414  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4415 
4416  fprintf(stderr, "%s", PQerrorMessage(con));
4417  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4418  {
4419  fprintf(stderr, "Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"\n", PQdb(con));
4420  }
4421 
4422  exit(1);
4423  }
4424  scale = atoi(PQgetvalue(res, 0, 0));
4425  if (scale < 0)
4426  {
4427  fprintf(stderr, "invalid count(*) from pgbench_branches: \"%s\"\n",
4428  PQgetvalue(res, 0, 0));
4429  exit(1);
4430  }
4431  PQclear(res);
4432 
4433  /* warn if we override user-given -s switch */
4434  if (scale_given)
4435  fprintf(stderr,
4436  "scale option ignored, using count from pgbench_branches table (%d)\n",
4437  scale);
4438  }
4439 
4440  /*
4441  * :scale variables normally get -s or database scale, but don't override
4442  * an explicit -D switch
4443  */
4444  if (lookupVariable(&state[0], "scale") == NULL)
4445  {
4446  for (i = 0; i < nclients; i++)
4447  {
4448  if (!putVariableInt(&state[i], "startup", "scale", scale))
4449  exit(1);
4450  }
4451  }
4452 
4453  /*
4454  * Define a :client_id variable that is unique per connection. But don't
4455  * override an explicit -D switch.
4456  */
4457  if (lookupVariable(&state[0], "client_id") == NULL)
4458  {
4459  for (i = 0; i < nclients; i++)
4460  {
4461  if (!putVariableInt(&state[i], "startup", "client_id", i))
4462  exit(1);
4463  }
4464  }
4465 
4466  if (!is_no_vacuum)
4467  {
4468  fprintf(stderr, "starting vacuum...");
4469  tryExecuteStatement(con, "vacuum pgbench_branches");
4470  tryExecuteStatement(con, "vacuum pgbench_tellers");
4471  tryExecuteStatement(con, "truncate pgbench_history");
4472  fprintf(stderr, "end.\n");
4473 
4474  if (do_vacuum_accounts)
4475  {
4476  fprintf(stderr, "starting vacuum pgbench_accounts...");
4477  tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
4478  fprintf(stderr, "end.\n");
4479  }
4480  }
4481  PQfinish(con);
4482 
4483  /* set random seed */
4484  INSTR_TIME_SET_CURRENT(start_time);
4485  srandom((unsigned int) INSTR_TIME_GET_MICROSEC(start_time));
4486 
4487  /* set up thread data structures */
4488  threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
4489  nclients_dealt = 0;
4490 
4491  for (i = 0; i < nthreads; i++)
4492  {
4493  TState *thread = &threads[i];
4494 
4495  thread->tid = i;
4496  thread->state = &state[nclients_dealt];
4497  thread->nstate =
4498  (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
4499  thread->random_state[0] = random();
4500  thread->random_state[1] = random();
4501  thread->random_state[2] = random();
4502  thread->logfile = NULL; /* filled in later */
4503  thread->latency_late = 0;
4504  initStats(&thread->stats, 0);
4505 
4506  nclients_dealt += thread->nstate;
4507  }
4508 
4509  /* all clients must be assigned to a thread */
4510  Assert(nclients_dealt == nclients);
4511 
4512  /* get start up time */
4513  INSTR_TIME_SET_CURRENT(start_time);
4514 
4515  /* set alarm if duration is specified. */
4516  if (duration > 0)
4517  setalarm(duration);
4518 
4519  /* start threads */
4520 #ifdef ENABLE_THREAD_SAFETY
4521  for (i = 0; i < nthreads; i++)
4522  {
4523  TState *thread = &threads[i];
4524 
4526 
4527  /* compute when to stop */
4528  if (duration > 0)
4530  (int64) 1000000 * duration;
4531 
4532  /* the first thread (i = 0) is executed by main thread */
4533  if (i > 0)
4534  {
4535  int err = pthread_create(&thread->thread, NULL, threadRun, thread);
4536 
4537  if (err != 0 || thread->thread == INVALID_THREAD)
4538  {
4539  fprintf(stderr, "could not create thread: %s\n", strerror(err));
4540  exit(1);
4541  }
4542  }
4543  else
4544  {
4545  thread->thread = INVALID_THREAD;
4546  }
4547  }
4548 #else
4549  INSTR_TIME_SET_CURRENT(threads[0].start_time);
4550  /* compute when to stop */
4551  if (duration > 0)
4552  end_time = INSTR_TIME_GET_MICROSEC(threads[0].start_time) +
4553  (int64) 1000000 * duration;
4554  threads[0].thread = INVALID_THREAD;
4555 #endif /* ENABLE_THREAD_SAFETY */
4556 
4557  /* wait for threads and accumulate results */
4558  initStats(&stats, 0);
4559  INSTR_TIME_SET_ZERO(conn_total_time);
4560  for (i = 0; i < nthreads; i++)
4561  {
4562  TState *thread = &threads[i];
4563 
4564 #ifdef ENABLE_THREAD_SAFETY
4565  if (threads[i].thread == INVALID_THREAD)
4566  /* actually run this thread directly in the main thread */
4567  (void) threadRun(thread);
4568  else
4569  /* wait of other threads. should check that 0 is returned? */
4570  pthread_join(thread->thread, NULL);
4571 #else
4572  (void) threadRun(thread);
4573 #endif /* ENABLE_THREAD_SAFETY */
4574 
4575  /* aggregate thread level stats */
4576  mergeSimpleStats(&stats.latency, &thread->stats.latency);
4577  mergeSimpleStats(&stats.lag, &thread->stats.lag);
4578  stats.cnt += thread->stats.cnt;
4579  stats.skipped += thread->stats.skipped;
4580  latency_late += thread->latency_late;
4581  INSTR_TIME_ADD(conn_total_time, thread->conn_time);
4582  }
4583  disconnect_all(state, nclients);
4584 
4585  /*
4586  * XXX We compute results as though every client of every thread started
4587  * and finished at the same time. That model can diverge noticeably from
4588  * reality for a short benchmark run involving relatively many threads.
4589  * The first thread may process notably many transactions before the last
4590  * thread begins. Improving the model alone would bring limited benefit,
4591  * because performance during those periods of partial thread count can
4592  * easily exceed steady state performance. This is one of the many ways
4593  * short runs convey deceptive performance figures.
4594  */
4595  INSTR_TIME_SET_CURRENT(total_time);
4596  INSTR_TIME_SUBTRACT(total_time, start_time);
4597  printResults(threads, &stats, total_time, conn_total_time, latency_late);
4598 
4599  return 0;
4600 }
static void checkInitSteps(const char *initialize_steps)
Definition: pgbench.c:2968
static const BuiltinScript * findBuiltin(const char *name)
Definition: pgbench.c:3565
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6106
double sample_rate
Definition: pgbench.c:124
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:948
static bool putVariableNumber(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1141
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:61
#define INVALID_THREAD
Definition: pgbench.c:353
int id
Definition: pgbench.c:309
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3118
static int num_scripts
Definition: pgbench.c:403
unsigned short random_state[3]
Definition: pgbench.c:342
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static void listAvailableScripts(void)
Definition: pgbench.c:3553
char * name
Definition: pgbench.c:198
int nclients
Definition: pgbench.c:171
const char * get_progname(const char *argv0)
Definition: path.c:453
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
long random(void)
Definition: random.c:22
static int parseScriptWeight(const char *option, char **script)
Definition: pgbench.c:3602
#define DEFAULT_INIT_STEPS
Definition: pgbench.c:93
struct timeval instr_time
Definition: instr_time.h:147
int64 latency_late
Definition: pgbench.c:350
SimpleStats lag
Definition: pgbench.c:233
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:793
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3629
int scale
Definition: pgbench.c:108
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:151
bool use_log
Definition: pgbench.c:164
static bool putVariable(CState *st, const char *context, char *name, const char *value)
Definition: pgbench.c:1118
SimpleStats latency
Definition: pgbench.c:232
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
static void process_file(const char *filename, int weight)
Definition: pgbench.c:3512
bool per_script_stats
Definition: pgbench.c:168
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
bool use_quiet
Definition: pgbench.c:165
int duration
Definition: pgbench.c:101
static time_t start_time
Definition: pg_ctl.c:95
bool is_connect
Definition: pgbench.c:173
Variable * variables
Definition: pgbench.c:316
int nstate
Definition: pgbench.c:341
static const char * QUERYMODE[]
Definition: pgbench.c:380
int64 end_time
Definition: pgbench.c:102
#define required_argument
Definition: getopt_long.h:25
FILE * logfile
Definition: pgbench.c:344
static void mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
Definition: pgbench.c:777
int optind
Definition: getopt.c:51
int64 cnt
Definition: pgbench.c:229
CState * state
Definition: pgbench.c:340
int fillfactor
Definition: pgbench.c:114
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
static int debug
Definition: pgbench.c:407
char * c
int nxacts
Definition: pgbench.c:100
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:155
static void disconnect_all(CState *state, int length)
Definition: pgbench.c:2622
bool is_numeric
Definition: pgbench.c:200
char * tablespace
Definition: pgbench.c:143
static void usage(void)
Definition: pgbench.c:478
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
instr_time start_time
Definition: pgbench.c:347
char * index_tablespace
Definition: pgbench.c:144
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
int nthreads
Definition: pgbench.c:172
char * value
Definition: pgbench.c:199
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
static bool parseQuery(Command *cmd)
Definition: pgbench.c:3043
int64 skipped
Definition: pgbench.c:230
static int64 total_weight
Definition: pgbench.c:405
char * pghost
Definition: pgbench.c:177
int progress
Definition: pgbench.c:169
#define no_argument
Definition: getopt_long.h:24
static bool putVariableInt(CState *st, const char *context, char *name, int64 value)
Definition: pgbench.c:1162
#define SQL_COMMAND
Definition: pgbench.c:358
static void * threadRun(void *arg)
Definition: pgbench.c:4603
#define MAXCLIENTS
Definition: pgbench.c:90
void PQclear(PGresult *res)
Definition: fe-exec.c:671
static void printResults(TState *threads, StatsData *total, instr_time total_time, instr_time conn_total_time, int latency_late)
Definition: pgbench.c:3677
bool progress_timestamp
Definition: pgbench.c:170
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5974
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2709
static PGconn * doConnect(void)
Definition: pgbench.c:857
#define Assert(condition)
Definition: c.h:670
Definition: regguts.h:298
const char * progname
Definition: pgbench.c:182
char * logfile_prefix
Definition: pgbench.c:181
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
Command ** commands
Definition: pgbench.c:398
static QueryMode querymode
Definition: pgbench.c:379
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int64 latency_limit
Definition: pgbench.c:138
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
pthread_t thread
Definition: pgbench.c:339
int main_pid
Definition: pgbench.c:175
int nvariables
Definition: pgbench.c:317
bool unlogged_tables
Definition: pgbench.c:119
char * dbName
Definition: pgbench.c:180
int64 throttle_delay
Definition: pgbench.c:130
char * optarg
Definition: getopt.c:53
StatsData stats
Definition: pgbench.c:349
int i
const char * strerror(int errnum)
Definition: strerror.c:19
static void process_builtin(const BuiltinScript *bi, int weight)
Definition: pgbench.c:3546
instr_time conn_time
Definition: pgbench.c:348
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897
void srandom(unsigned int seed)
Definition: srandom.c:22
int tid
Definition: pgbench.c:338
static void tryExecuteStatement(PGconn *con, const char *sql)
Definition: pgbench.c:842
#define DEFAULT_NXACTS
Definition: pgbench.c:96
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6053
static void setalarm(int seconds)
Definition: pgbench.c:4979
static void runInitSteps(const char *initialize_steps)
Definition: pgbench.c:2994
#define _(x)
Definition: elog.c:84
char * pgport
Definition: pgbench.c:178
bool is_latencies
Definition: pgbench.c:174
char * login
Definition: pgbench.c:179
int agg_interval
Definition: pgbench.c:166
PgBenchValue num_value
Definition: pgbench.c:201

◆ makeVariableNumeric()

static bool makeVariableNumeric ( Variable var)
static

Definition at line 1004 of file pgbench.c.

References is_an_int(), Variable::is_numeric, Variable::name, Variable::num_value, setDoubleValue(), setIntValue(), strtoint64(), and Variable::value.

Referenced by evaluateExpr().

1005 {
1006  if (var->is_numeric)
1007  return true; /* no work */
1008 
1009  if (is_an_int(var->value))
1010  {
1011  setIntValue(&var->num_value, strtoint64(var->value));
1012  var->is_numeric = true;
1013  }
1014  else /* type should be double */
1015  {
1016  double dv;
1017  char xs;
1018 
1019  if (sscanf(var->value, "%lf%c", &dv, &xs) != 1)
1020  {
1021  fprintf(stderr,
1022  "malformed variable \"%s\" value: \"%s\"\n",
1023  var->name, var->value);
1024  return false;
1025  }
1026  setDoubleValue(&var->num_value, dv);
1027  var->is_numeric = true;
1028  }
1029  return true;
1030 }
char * name
Definition: pgbench.c:198
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1317
int64 strtoint64(const char *str)
Definition: pgbench.c:573
bool is_numeric
Definition: pgbench.c:200
char * value
Definition: pgbench.c:199
static bool is_an_int(const char *str)
Definition: pgbench.c:541
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1309
PgBenchValue num_value
Definition: pgbench.c:201

◆ mergeSimpleStats()

static void mergeSimpleStats ( SimpleStats acc,
SimpleStats ss 
)
static

Definition at line 777 of file pgbench.c.

References SimpleStats::count, SimpleStats::max, SimpleStats::min, SimpleStats::sum, and SimpleStats::sum2.

Referenced by main(), and threadRun().

778 {
779  if (acc->count == 0 || ss->min < acc->min)
780  acc->min = ss->min;
781  if (acc->count == 0 || ss->max > acc->max)
782  acc->max = ss->max;
783  acc->count += ss->count;
784  acc->sum += ss->sum;
785  acc->sum2 += ss->sum2;
786 }
double sum
Definition: pgbench.c:218
int64 count
Definition: pgbench.c:215
double max
Definition: pgbench.c:217
double sum2
Definition: pgbench.c:219
double min
Definition: pgbench.c:216

◆ parseQuery()

static bool parseQuery ( Command cmd)
static

Definition at line 3043 of file pgbench.c.

References Command::argc, Command::argv, MAX_ARGS, name, parseVariable(), pg_free(), pg_strdup(), and replaceVariable().

Referenced by main().

3044 {
3045  char *sql,
3046  *p;
3047 
3048  /* We don't want to scribble on cmd->argv[0] until done */
3049  sql = pg_strdup(cmd->argv[0]);
3050 
3051  cmd->argc = 1;
3052 
3053  p = sql;
3054  while ((p = strchr(p, ':')) != NULL)
3055  {
3056  char var[12];
3057  char *name;
3058  int eaten;
3059 
3060  name = parseVariable(p, &eaten);
3061  if (name == NULL)
3062  {
3063  while (*p == ':')
3064  {
3065  p++;
3066  }
3067  continue;
3068  }
3069 
3070  if (cmd->argc >= MAX_ARGS)
3071  {
3072  fprintf(stderr, "statement has too many arguments (maximum is %d): %s\n",
3073  MAX_ARGS - 1, cmd->argv[0]);
3074  pg_free(name);
3075  return false;
3076  }
3077 
3078  sprintf(var, "$%d", cmd->argc);
3079  p = replaceVariable(&sql, p, eaten, var);
3080 
3081  cmd->argv[cmd->argc] = name;
3082  cmd->argc++;
3083  }
3084 
3085  pg_free(cmd->argv[0]);
3086  cmd->argv[0] = sql;
3087  return true;
3088 }
char * argv[MAX_ARGS]
Definition: pgbench.c:389
#define MAX_ARGS
Definition: pgbench.c:360
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1202
int argc
Definition: pgbench.c:388
void pg_free(void *ptr)
Definition: fe_memutils.c:105
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1179
const char * name
Definition: encode.c:521

◆ ParseScript()

static void ParseScript ( const char *  script,
const char *  desc,
int  weight 
)
static

Definition at line 3380 of file pgbench.c.

References addScript(), ParsedScript::commands, COMMANDS_ALLOC_NUM, ParsedScript::desc, initPQExpBuffer(), initStats(), pg_malloc(), pg_realloc(), process_backslash_command(), process_sql_command(), PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, psql_scan(), psql_scan_create(), psql_scan_destroy(), psql_scan_finish(), psql_scan_setup(), resetPQExpBuffer(), ParsedScript::stats, termPQExpBuffer(), and ParsedScript::weight.

Referenced by process_builtin(), and process_file().

3381 {
3382  ParsedScript ps;
3383  PsqlScanState sstate;
3384  PQExpBufferData line_buf;
3385  int alloc_num;
3386  int index;
3387 
3388 #define COMMANDS_ALLOC_NUM 128
3389  alloc_num = COMMANDS_ALLOC_NUM;
3390 
3391  /* Initialize all fields of ps */
3392  ps.desc = desc;
3393  ps.weight = weight;
3394  ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
3395  initStats(&ps.stats, 0);
3396 
3397  /* Prepare to parse script */
3399 
3400  /*
3401  * Ideally, we'd scan scripts using the encoding and stdstrings settings
3402  * we get from a DB connection. However, without major rearrangement of
3403  * pgbench's argument parsing, we can't have a DB connection at the time
3404  * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
3405  * with any backend-safe encoding, though conceivably we could be fooled
3406  * if a script file uses a client-only encoding. We also assume that
3407  * stdstrings should be true, which is a bit riskier.
3408  */
3409  psql_scan_setup(sstate, script, strlen(script), 0, true);
3410 
3411  initPQExpBuffer(&line_buf);
3412 
3413  index = 0;
3414 
3415  for (;;)
3416  {
3417  PsqlScanResult sr;
3418  promptStatus_t prompt;
3419  Command *command;
3420 
3421  resetPQExpBuffer(&line_buf);
3422 
3423  sr = psql_scan(sstate, &line_buf, &prompt);
3424 
3425  /* If we collected a SQL command, process that */
3426  command = process_sql_command(&line_buf, desc);
3427  if (command)
3428  {
3429  ps.commands[index] = command;
3430  index++;
3431 
3432  if (index >= alloc_num)
3433  {
3434  alloc_num += COMMANDS_ALLOC_NUM;
3435  ps.commands = (Command **)
3436  pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
3437  }
3438  }
3439 
3440  /* If we reached a backslash, process that */
3441  if (sr == PSCAN_BACKSLASH)
3442  {
3443  command = process_backslash_command(sstate, desc);
3444  if (command)
3445  {
3446  ps.commands[index] = command;
3447  index++;
3448 
3449  if (index >= alloc_num)
3450  {
3451  alloc_num += COMMANDS_ALLOC_NUM;
3452  ps.commands = (Command **)
3453  pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
3454  }
3455  }
3456  }
3457 
3458  /* Done if we reached EOF */
3459  if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
3460  break;
3461  }
3462 
3463  ps.commands[index] = NULL;
3464 
3465  addScript(ps);
3466 
3467  termPQExpBuffer(&line_buf);
3468  psql_scan_finish(sstate);
3469  psql_scan_destroy(sstate);
3470 }
PsqlScanResult
Definition: psqlscan.h:30
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static Command * process_sql_command(PQExpBuffer buf, const char *source)
Definition: pgbench.c:3152
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
static void static void addScript(ParsedScript script)
Definition: pgbench.c:3646
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:471
#define COMMANDS_ALLOC_NUM
StatsData stats
Definition: pgbench.c:399
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:793
int weight
Definition: pgbench.c:397
Definition: type.h:89
const char * desc
Definition: pgbench.c:396
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
void psql_scan_destroy(PsqlScanState state)
enum _promptStatus promptStatus_t
Command ** commands
Definition: pgbench.c:398
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
static Command * process_backslash_command(PsqlScanState sstate, const char *source)
Definition: pgbench.c:3216
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
void psql_scan_finish(PsqlScanState state)
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89

◆ parseScriptWeight()

static int parseScriptWeight ( const char *  option,
char **  script 
)
static

Definition at line 3602 of file pgbench.c.

References INT64_FORMAT, pg_malloc(), pg_strdup(), and WSEP.

Referenced by main().

3603 {
3604  char *sep;
3605  int weight;
3606 
3607  if ((sep = strrchr(option, WSEP)))
3608  {
3609  int namelen = sep - option;
3610  long wtmp;
3611  char *badp;
3612 
3613  /* generate the script name */
3614  *script = pg_malloc(namelen + 1);
3615  strncpy(*script, option, namelen);
3616  (*script)[namelen] = '\0';
3617 
3618  /* process digits of the weight spec */
3619  errno = 0;
3620  wtmp = strtol(sep + 1, &badp, 10);
3621  if (errno != 0 || badp == sep + 1 || *badp != '\0')
3622  {
3623  fprintf(stderr, "invalid weight specification: %s\n", sep);
3624  exit(1);
3625  }
3626  if (wtmp > INT_MAX || wtmp < 0)
3627  {
3628  fprintf(stderr,
3629  "weight specification out of range (0 .. %u): " INT64_FORMAT "\n",
3630  INT_MAX, (int64) wtmp);
3631  exit(1);
3632  }
3633  weight = wtmp;
3634  }
3635  else
3636  {
3637  *script = pg_strdup(option);
3638  weight = 1;
3639  }
3640 
3641  return weight;
3642 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define WSEP
Definition: pgbench.c:184
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define INT64_FORMAT
Definition: c.h:338

◆ parseVariable()

static char* parseVariable ( const char *  sql,
int *  eaten 
)
static

Definition at line 1179 of file pgbench.c.

References i, IS_HIGHBIT_SET, name, and pg_malloc().

Referenced by assignVariables(), and parseQuery().

1180 {
1181  int i = 0;
1182  char *name;
1183 
1184  do
1185  {
1186  i++;
1187  } while (IS_HIGHBIT_SET(sql[i]) ||
1188  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1189  "_0123456789", sql[i]) != NULL);
1190  if (i == 1)
1191  return NULL; /* no valid variable name chars */
1192 
1193  name = pg_malloc(i);
1194  memcpy(name, &sql[1], i - 1);
1195  name[i - 1] = '\0';
1196 
1197  *eaten = i;
1198  return name;
1199 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define IS_HIGHBIT_SET(ch)
Definition: c.h:939
const char * name
Definition: encode.c:521
int i

◆ pgbench_error()

static void pgbench_error ( const char *  fmt,
  ... 
)
static

Definition at line 3094 of file pgbench.c.

References _.

3095 {
3096  va_list ap;
3097 
3098  fflush(stdout);
3099  va_start(ap, fmt);
3100  vfprintf(stderr, _(fmt), ap);
3101  va_end(ap);
3102 }
#define _(x)
Definition: elog.c:84

◆ preparedStatementName()

static void preparedStatementName ( char *  buffer,
int  file,
int  state 
)
static

Definition at line 1866 of file pgbench.c.

Referenced by sendCommand().

1867 {
1868  sprintf(buffer, "P%d_%d", file, state);
1869 }
Definition: regguts.h:298
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214

◆ printResults()

static void printResults ( TState threads,
StatsData total,
instr_time  total_time,
instr_time  conn_total_time,
int  latency_late 
)
static

Definition at line 3677 of file pgbench.c.

References StatsData::cnt, i, INSTR_TIME_GET_DOUBLE, INT64_FORMAT, StatsData::lag, StatsData::latency, SimpleStats::max, nclients, num_scripts, printSimpleStats(), StatsData::skipped, ParsedScript::stats, and SimpleStats::sum.

Referenced by main().

3679 {
3680  double time_include,
3681  tps_include,
3682  tps_exclude;
3683 
3684  time_include = INSTR_TIME_GET_DOUBLE(total_time);
3685  tps_include = total->cnt / time_include;
3686  tps_exclude = total->cnt / (time_include -
3687  (INSTR_TIME_GET_DOUBLE(conn_total_time) / nclients));
3688 
3689  /* Report test parameters. */
3690  printf("transaction type: %s\n",
3691  num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
3692  printf("scaling factor: %d\n", scale);
3693  printf("query mode: %s\n", QUERYMODE[querymode]);
3694  printf("number of clients: %d\n", nclients);
3695  printf("number of threads: %d\n", nthreads);
3696  if (duration <= 0)
3697  {
3698  printf("number of transactions per client: %d\n", nxacts);
3699  printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
3700  total->cnt - total->skipped, nxacts * nclients);
3701  }
3702  else
3703  {
3704  printf("duration: %d s\n", duration);
3705  printf("number of transactions actually processed: " INT64_FORMAT "\n",
3706  total->cnt);
3707  }
3708 
3709  /* Remaining stats are nonsensical if we failed to execute any xacts */
3710  if (total->cnt <= 0)
3711  return;
3712 
3714  printf("number of transactions skipped: " INT64_FORMAT " (%.3f %%)\n",
3715  total->skipped,
3716  100.0 * total->skipped / total->cnt);
3717 
3718  if (latency_limit)
3719  printf("number of transactions above the %.1f ms latency limit: %d (%.3f %%)\n",
3720  latency_limit / 1000.0, latency_late,
3721  100.0 * latency_late / total->cnt);
3722 
3724  printSimpleStats("latency", &total->latency);
3725  else
3726  {
3727  /* no measurement, show average latency computed from run time */
3728  printf("latency average = %.3f ms\n",
3729  1000.0 * time_include * nclients / total->cnt);
3730  }
3731 
3732  if (throttle_delay)
3733  {
3734  /*
3735  * Report average transaction lag under rate limit throttling. This
3736  * is the delay between scheduled and actual start times for the
3737  * transaction. The measured lag may be caused by thread/client load,
3738  * the database load, or the Poisson throttling process.
3739  */
3740  printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
3741  0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
3742  }
3743 
3744  printf("tps = %f (including connections establishing)\n", tps_include);
3745  printf("tps = %f (excluding connections establishing)\n", tps_exclude);
3746 
3747  /* Report per-script/command statistics */
3749  {
3750  int i;
3751 
3752  for (i = 0; i < num_scripts; i++)
3753  {
3754  if (num_scripts > 1)
3755  printf("SQL script %d: %s\n"
3756  " - weight: %d (targets %.1f%% of total)\n"
3757  " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n",
3758  i + 1, sql_script[i].desc,
3759  sql_script[i].weight,
3760  100.0 * sql_script[i].weight / total_weight,
3761  sql_script[i].stats.cnt,
3762  100.0 * sql_script[i].stats.cnt / total->cnt,
3763  sql_script[i].stats.cnt / time_include);
3764  else
3765  printf("script statistics:\n");
3766 
3767  if (latency_limit)
3768  printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
3769  sql_script[i].stats.skipped,
3770  100.0 * sql_script[i].stats.skipped / sql_script[i].stats.cnt);
3771 
3772  if (num_scripts > 1)
3773  printSimpleStats(" - latency", &sql_script[i].stats.latency);
3774 
3775  /* Report per-command latencies */
3776  if (is_latencies)
3777  {
3778  Command **commands;
3779 
3780  printf(" - statement latencies in milliseconds:\n");
3781 
3782  for (commands = sql_script[i].commands;
3783  *commands != NULL;
3784  commands++)
3785  printf(" %11.3f %s\n",
3786  1000.0 * (*commands)->stats.sum /
3787  (*commands)->stats.count,
3788  (*commands)->line);
3789  }
3790  }
3791  }
3792 }
static void printSimpleStats(const char *prefix, SimpleStats *ss)
Definition: pgbench.c:3665
static int num_scripts
Definition: pgbench.c:403
int nclients
Definition: pgbench.c:171
SimpleStats lag
Definition: pgbench.c:233
StatsData stats
Definition: pgbench.c:399
double sum
Definition: pgbench.c:218
int scale
Definition: pgbench.c:108
SimpleStats latency
Definition: pgbench.c:232
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool per_script_stats
Definition: pgbench.c:168
int duration
Definition: pgbench.c:101
static const char * QUERYMODE[]
Definition: pgbench.c:380
int64 cnt
Definition: pgbench.c:229
int nxacts
Definition: pgbench.c:100
int nthreads
Definition: pgbench.c:172
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
int64 skipped
Definition: pgbench.c:230
static int64 total_weight
Definition: pgbench.c:405
int progress
Definition: pgbench.c:169
double max
Definition: pgbench.c:217
static QueryMode querymode
Definition: pgbench.c:379
int64 latency_limit
Definition: pgbench.c:138
#define INT64_FORMAT
Definition: c.h:338
int64 throttle_delay
Definition: pgbench.c:130
int i
bool is_latencies
Definition: pgbench.c:174

◆ printSimpleStats()

static void printSimpleStats ( const char *  prefix,
SimpleStats ss 
)
static

Definition at line 3665 of file pgbench.c.

References SimpleStats::count, SimpleStats::sum, and SimpleStats::sum2.

Referenced by printResults().

3666 {
3667  /* print NaN if no transactions where executed */
3668  double latency = ss->sum / ss->count;
3669  double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
3670 
3671  printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
3672  printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
3673 }
double sum
Definition: pgbench.c:218
int64 count
Definition: pgbench.c:215
double sum2
Definition: pgbench.c:219

◆ process_backslash_command()

static Command* process_backslash_command ( PsqlScanState  sstate,
const char *  source 
)
static

Definition at line 3216 of file pgbench.c.

References Command::argc, Command::argv, Command::command_num, PQExpBufferData::data, Command::expr, expr_lex_one_word(), expr_parse_result, expr_scanner_finish(), expr_scanner_get_lineno(), expr_scanner_get_substring(), expr_scanner_init(), expr_scanner_offset(), expr_yyparse(), getMetaCommand(), initPQExpBuffer(), initSimpleStats(), Command::line, MAX_ARGS, Command::meta, META_COMMAND, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, pg_malloc0(), pg_strcasecmp(), pg_strdup(), Command::stats, syntax_error(), termPQExpBuffer(), Command::type, and yyscanner.

Referenced by ParseScript().

3217 {
3218  Command *my_command;
3219  PQExpBufferData word_buf;
3220  int word_offset;
3221  int offsets[MAX_ARGS]; /* offsets of argument words */
3222  int start_offset;
3223  int lineno;
3224  int j;
3225 
3226  initPQExpBuffer(&word_buf);
3227 
3228  /* Remember location of the backslash */
3229  start_offset = expr_scanner_offset(sstate) - 1;
3230  lineno = expr_scanner_get_lineno(sstate, start_offset);
3231 
3232  /* Collect first word of command */
3233  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
3234  {
3235  termPQExpBuffer(&word_buf);
3236  return NULL;
3237  }
3238 
3239  /* Allocate and initialize Command structure */
3240  my_command = (Command *) pg_malloc0(sizeof(Command));
3241  my_command->command_num = num_commands++;
3242  my_command->type = META_COMMAND;
3243  my_command->argc = 0;
3244  initSimpleStats(&my_command->stats);
3245 
3246  /* Save first word (command name) */
3247  j = 0;
3248  offsets[j] = word_offset;
3249  my_command->argv[j++] = pg_strdup(word_buf.data);
3250  my_command->argc++;
3251 
3252  /* ... and convert it to enum form */
3253  my_command->meta = getMetaCommand(my_command->argv[0]);
3254 
3255  if (my_command->meta == META_SET)
3256  {
3257  /* For \set, collect var name, then lex the expression. */
3259 
3260  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
3261  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3262  "missing argument", NULL, -1);
3263 
3264  offsets[j] = word_offset;
3265  my_command->argv[j++] = pg_strdup(word_buf.data);
3266  my_command->argc++;
3267 
3268  yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
3269  my_command->argv[0]);
3270 
3271  if (expr_yyparse(yyscanner) != 0)
3272  {
3273  /* dead code: exit done from syntax_error called by yyerror */
3274  exit(1);
3275  }
3276 
3277  my_command->expr = expr_parse_result;
3278 
3279  /* Save line, trimming any trailing newline */
3280  my_command->line = expr_scanner_get_substring(sstate,
3281  start_offset,
3282  expr_scanner_offset(sstate),
3283  true);
3284 
3285  expr_scanner_finish(yyscanner);
3286 
3287  termPQExpBuffer(&word_buf);
3288 
3289  return my_command;
3290  }
3291 
3292  /* For all other commands, collect remaining words. */
3293  while (expr_lex_one_word(sstate, &word_buf, &word_offset))
3294  {
3295  if (j >= MAX_ARGS)
3296  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3297  "too many arguments", NULL, -1);
3298 
3299  offsets[j] = word_offset;
3300  my_command->argv[j++] = pg_strdup(word_buf.data);
3301  my_command->argc++;
3302  }
3303 
3304  /* Save line, trimming any trailing newline */
3305  my_command->line = expr_scanner_get_substring(sstate,
3306  start_offset,
3307  expr_scanner_offset(sstate),
3308  true);
3309 
3310  if (my_command->meta == META_SLEEP)
3311  {
3312  if (my_command->argc < 2)
3313  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3314  "missing argument", NULL, -1);
3315 
3316  if (my_command->argc > 3)
3317  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3318  "too many arguments", NULL,
3319  offsets[3] - start_offset);
3320 
3321  /*
3322  * Split argument into number and unit to allow "sleep 1ms" etc. We
3323  * don't have to terminate the number argument with null because it
3324  * will be parsed with atoi, which ignores trailing non-digit
3325  * characters.
3326  */
3327  if (my_command->argc == 2 && my_command->argv[1][0] != ':')
3328  {
3329  char *c = my_command->argv[1];
3330 
3331  while (isdigit((unsigned char) *c))
3332  c++;
3333  if (*c)
3334  {
3335  my_command->argv[2] = c;
3336  offsets[2] = offsets[1] + (c - my_command->argv[1]);
3337  my_command->argc = 3;
3338  }
3339  }
3340 
3341  if (my_command->argc == 3)
3342  {
3343  if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
3344  pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
3345  pg_strcasecmp(my_command->argv[2], "s") != 0)
3346  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3347  "unrecognized time unit, must be us, ms or s",
3348  my_command->argv[2], offsets[2] - start_offset);
3349  }
3350  }
3351  else if (my_command->meta == META_SETSHELL)
3352  {
3353  if (my_command->argc < 3)
3354  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3355  "missing argument", NULL, -1);
3356  }
3357  else if (my_command->meta == META_SHELL)
3358  {
3359  if (my_command->argc < 2)
3360  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3361  "missing command", NULL, -1);
3362  }
3363  else
3364  {
3365  /* my_command->meta == META_NONE */
3366  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3367  "invalid command", NULL, -1);
3368  }
3369 
3370  termPQExpBuffer(&word_buf);
3371 
3372  return my_command;
3373 }
void expr_scanner_finish(yyscan_t yyscanner)
int type
Definition: pgbench.c:386
int command_num
Definition: pgbench.c:385
int expr_yyparse(yyscan_t yyscanner)
char * line
Definition: pgbench.c:384
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
yyscan_t expr_scanner_init(PsqlScanState state, const char *source, int lineno, int start_offset, const char *command)
void syntax_error(const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
Definition: pgbench.c:3117
PgBenchExpr * expr
Definition: pgbench.c:390
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * argv[MAX_ARGS]
Definition: pgbench.c:389
#define MAX_ARGS
Definition: pgbench.c:360
int expr_scanner_get_lineno(PsqlScanState state, int offset)
#define META_COMMAND
Definition: pgbench.c:359
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
char * c
PgBenchExpr * expr_parse_result
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
MetaCommand meta
Definition: pgbench.c:387
int expr_scanner_offset(PsqlScanState state)
int argc
Definition: pgbench.c:388
SimpleStats stats
Definition: pgbench.c:391
void * yyscan_t
Definition: psqlscan_int.h:60
char * expr_scanner_get_substring(PsqlScanState state, int start_offset, int end_offset, bool chomp)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:210
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:753
static int num_commands
Definition: pgbench.c:404
bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
static MetaCommand getMetaCommand(const char *cmd)
Definition: pgbench.c:1737
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89

◆ process_builtin()

static void process_builtin ( const BuiltinScript bi,
int  weight 
)
static

Definition at line 3546 of file pgbench.c.

References BuiltinScript::desc, ParseScript(), and BuiltinScript::script.

Referenced by main().

3547 {
3548  ParseScript(bi->script, bi->desc, weight);
3549 }
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:3380
const char * desc
Definition: pgbench.c:413
const char * script
Definition: pgbench.c:414

◆ process_file()

static void process_file ( const char *  filename,
int  weight 
)
static

Definition at line 3512 of file pgbench.c.

References buf, fd(), free, ParseScript(), read_file_contents(), and strerror().

Referenced by main(), and process_psqlrc_file().

3513 {
3514  FILE *fd;
3515  char *buf;
3516 
3517  /* Slurp the file contents into "buf" */
3518  if (strcmp(filename, "-") == 0)
3519  fd = stdin;
3520  else if ((fd = fopen(filename, "r")) == NULL)
3521  {
3522  fprintf(stderr, "could not open file \"%s\": %s\n",
3523  filename, strerror(errno));
3524  exit(1);
3525  }
3526 
3527  buf = read_file_contents(fd);
3528 
3529  if (ferror(fd))
3530  {
3531  fprintf(stderr, "could not read file \"%s\": %s\n",
3532  filename, strerror(errno));
3533  exit(1);
3534  }
3535 
3536  if (fd != stdin)
3537  fclose(fd);
3538 
3539  ParseScript(buf, filename, weight);
3540 
3541  free(buf);
3542 }
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:3380
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static char * buf
Definition: pg_test_fsync.c:67
#define free(a)
Definition: header.h:65
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:3479
static char * filename
Definition: pg_dumpall.c:90
const char * strerror(int errnum)
Definition: strerror.c:19

◆ process_sql_command()

static Command* process_sql_command ( PQExpBuffer  buf,
const char *  source 
)
static

Definition at line 3152 of file pgbench.c.

References Command::argc, Command::argv, Command::command_num, PQExpBufferData::data, initSimpleStats(), Command::line, Command::meta, META_NONE, pg_malloc(), pg_malloc0(), pg_strdup(), SQL_COMMAND, Command::stats, and Command::type.

Referenced by ParseScript().

3153 {
3154  Command *my_command;
3155  char *p;
3156  char *nlpos;
3157 
3158  /* Skip any leading whitespace, as well as "--" style comments */
3159  p = buf->data;
3160  for (;;)
3161  {
3162  if (isspace((unsigned char) *p))
3163  p++;
3164  else if (strncmp(p, "--", 2) == 0)
3165  {
3166  p = strchr(p, '\n');
3167  if (p == NULL)
3168  return NULL;
3169  p++;
3170  }
3171  else
3172  break;
3173  }
3174 
3175  /* If there's nothing but whitespace and comments, we're done */
3176  if (*p == '\0')
3177  return NULL;
3178 
3179  /* Allocate and initialize Command structure */
3180  my_command = (Command *) pg_malloc0(sizeof(Command));
3181  my_command->command_num = num_commands++;
3182  my_command->type = SQL_COMMAND;
3183  my_command->meta = META_NONE;
3184  initSimpleStats(&my_command->stats);
3185 
3186  /*
3187  * Install query text as the sole argv string. If we are using a
3188  * non-simple query mode, we'll extract parameters from it later.
3189  */
3190  my_command->argv[0] = pg_strdup(p);
3191  my_command->argc = 1;
3192 
3193  /*
3194  * If SQL command is multi-line, we only want to save the first line as
3195  * the "line" label.
3196  */
3197  nlpos = strchr(p, '\n');
3198  if (nlpos)
3199  {
3200  my_command->line = pg_malloc(nlpos - p + 1);
3201  memcpy(my_command->line, p, nlpos - p);
3202  my_command->line[nlpos - p] = '\0';
3203  }
3204  else
3205  my_command->line = pg_strdup(p);
3206 
3207  return my_command;
3208 }
int type
Definition: pgbench.c:386
int command_num
Definition: pgbench.c:385
char * line
Definition: pgbench.c:384
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * argv[MAX_ARGS]
Definition: pgbench.c:389
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
MetaCommand meta
Definition: pgbench.c:387
int argc
Definition: pgbench.c:388
#define SQL_COMMAND
Definition: pgbench.c:358
SimpleStats stats
Definition: pgbench.c:391
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:753
static int num_commands
Definition: pgbench.c:404

◆ processXactStats()

static void processXactStats ( TState thread,
CState st,
instr_time now,
bool  skipped,
StatsData agg 
)
static

Definition at line 2575 of file pgbench.c.

References accumStats(), StatsData::cnt, CState::cnt, doLog(), INSTR_TIME_GET_MICROSEC, INSTR_TIME_IS_ZERO, INSTR_TIME_SET_CURRENT, TState::latency_late, latency_limit, per_script_stats, TState::stats, ParsedScript::stats, CState::txn_begin, CState::txn_scheduled, and CState::use_file.

Referenced by doCustom().

2577 {
2578  double latency = 0.0,
2579  lag = 0.0;
2580  bool thread_details = progress || throttle_delay || latency_limit,
2581  detailed = thread_details || use_log || per_script_stats;
2582 
2583  if (detailed && !skipped)
2584  {
2585  if (INSTR_TIME_IS_ZERO(*now))
2587 
2588  /* compute latency & lag */
2589  latency = INSTR_TIME_GET_MICROSEC(*now) - st->txn_scheduled;
2591  }
2592 
2593  if (thread_details)
2594  {
2595  /* keep detailed thread stats */
2596  accumStats(&thread->stats, skipped, latency, lag);
2597 
2598  /* count transactions over the latency limit, if needed */
2599  if (latency_limit && latency > latency_limit)
2600  thread->latency_late++;
2601  }
2602  else
2603  {
2604  /* no detailed stats, just count */
2605  thread->stats.cnt++;
2606  }
2607 
2608  /* client stat is just counting */
2609  st->cnt++;
2610 
2611  if (use_log)
2612  doLog(thread, st, agg, skipped, latency, lag);
2613 
2614  /* XXX could use a mutex here, but we choose not to */
2615  if (per_script_stats)
2616  accumStats(&sql_script[st->use_file].stats, skipped, latency, lag);
2617 }
int64 latency_late
Definition: pgbench.c:350
StatsData stats
Definition: pgbench.c:399
bool use_log
Definition: pgbench.c:164
bool per_script_stats
Definition: pgbench.c:168
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
int64 cnt
Definition: pgbench.c:229
int64 cnt
Definition: pgbench.c:329
int64 txn_scheduled
Definition: pgbench.c:321
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:402
int progress
Definition: pgbench.c:169
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:2494
instr_time txn_begin
Definition: pgbench.c:323
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:806
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
int64 latency_limit
Definition: pgbench.c:138
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
int64 throttle_delay
Definition: pgbench.c:130
StatsData stats
Definition: pgbench.c:349
int use_file
Definition: pgbench.c:312
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534

◆ putVariable()

static bool putVariable ( CState st,
const char *  context,
char *  name,
const char *  value 
)
static

Definition at line 1118 of file pgbench.c.

References free, Variable::is_numeric, lookupCreateVariable(), pg_strdup(), val, and Variable::value.

Referenced by main().

1119 {
1120  Variable *var;
1121  char *val;
1122 
1123  var = lookupCreateVariable(st, context, name);
1124  if (!var)
1125  return false;
1126 
1127  /* dup then free, in case value is pointing at this variable */
1128  val = pg_strdup(value);
1129 
1130  if (var->value)
1131  free(var->value);
1132  var->value = val;
1133  var->is_numeric = false;
1134 
1135  return true;
1136 }
static struct @121 value
bool is_numeric
Definition: pgbench.c:200
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * value
Definition: pgbench.c:199
static Variable * lookupCreateVariable(CState *st, const char *context, char *name)
Definition: pgbench.c:1072
#define free(a)
Definition: header.h:65
const char * name
Definition: encode.c:521
long val
Definition: informix.c:689

◆ putVariableInt()

static bool putVariableInt ( CState st,
const char *  context,
char *  name,
int64  value 
)
static

Definition at line 1162 of file pgbench.c.

References putVariableNumber(), setIntValue(), and val.

Referenced by main(), and runShellCommand().

1163 {
11